home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-01 | 181.8 KB | 5,580 lines |
-
- March 1995
-
-
-
-
-
-
-
-
-
- The CS-libraries
-
- Version: 1.6.b
-
-
-
-
- Theo van den Bout
- P.O. Box 3303
- 2280 GH Rijswijk
- The Netherlands
-
-
-
-
-
-
-
-
-
- Copyright (c) 1994,1995 by Combis, the Netherlands.
- All Rights Reserved.
-
-
-
-
- 1 Contents
-
- 1 Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 2 Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 2.1 Shareware. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 2.2 Contacting the Author. . . . . . . . . . . . . . . . . . . . . .
- 2.3 Registering. . . . . . . . . . . . . . . . . . . . . . . . . . .
- 2.4 Legal Matters. . . . . . . . . . . . . . . . . . . . . . . . . .
- 2.4.1 Disclaimer . . . . . . . . . . . . . . . . . . . . . . . .
- 2.4.2 Trademarks . . . . . . . . . . . . . . . . . . . . . . . .
-
- 3 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 4 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 5 Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 6 Runtime Libraries. . . . . . . . . . . . . . . . . . . . . . . . . . .
- 6.1 Using the libraries. . . . . . . . . . . . . . . . . . . . . . .
- 6.2 Compiler options . . . . . . . . . . . . . . . . . . . . . . . .
-
- 7 General Definitions & Functions. . . . . . . . . . . . . . . . . . . .
- 7.1 Portability. . . . . . . . . . . . . . . . . . . . . . . . . . .
- 7.2 Messages and errors. . . . . . . . . . . . . . . . . . . . . . .
- 7.3 Temporary Files. . . . . . . . . . . . . . . . . . . . . . . . .
-
- 8 Buffering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 9 PAGE-Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . .
- 9.2 Background . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 9.3 Storing data in the header-page. . . . . . . . . . . . . . . . .
-
- 10 TBASE-class . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 10.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 10.2 Using TBASE . . . . . . . . . . . . . . . . . . . . . . . . . .
- 10.3 Creating a Database . . . . . . . . . . . . . . . . . . . . . .
- 10.4 Opening . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 10.5 Closing . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 10.6 Appending Records . . . . . . . . . . . . . . . . . . . . . . .
- 10.7 Deleting Records. . . . . . . . . . . . . . . . . . . . . . . .
- 10.8 Advanced Topics . . . . . . . . . . . . . . . . . . . . . . . .
- 10.8.1 Page Utilization. . . . . . . . . . . . . . . . . . . . .
- 10.8.2 Locating Records. . . . . . . . . . . . . . . . . . . . .
- 10.9 Miscellaneous functions . . . . . . . . . . . . . . . . . . . .
- 10.10 Functions in alphabetical order. . . . . . . . . . . . . . . .
-
- 11 BTREE-class . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.2 BTREEx Classes. . . . . . . . . . . . . . . . . . . . . . . . .
- 11.3 Multiple Keys . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.4 Current Pointer . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5 Using Btrees. . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.1 Creating. . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.2 Opening . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.3 Inserting . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.4 Searching . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.5 Current . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.6 Deleting. . . . . . . . . . . . . . . . . . . . . . . . .
- 11.5.7 Closing . . . . . . . . . . . . . . . . . . . . . . . . .
- 11.6 Functions in alphabetical order.. . . . . . . . . . . . . . . .
-
- 12 CSDBGEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.2 Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.3 Features. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.4 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.5 Definition file . . . . . . . . . . . . . . . . . . . . . . . .
- 12.6 Tokenizing. . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.6.1 How does it work? . . . . . . . . . . . . . . . . . . . .
- 12.7 When is a substring indexed?. . . . . . . . . . . . . . . . . .
- 12.8 Export to dBASE . . . . . . . . . . . . . . . . . . . . . . . .
- 12.9 Exporting/Importing to/from ASCII . . . . . . . . . . . . . . .
- 12.10 Starting a new database. . . . . . . . . . . . . . . . . . . .
- 12.11 Opening a database . . . . . . . . . . . . . . . . . . . . . .
- 12.12 Current Record . . . . . . . . . . . . . . . . . . . . . . . .
- 12.13 Accessing fields . . . . . . . . . . . . . . . . . . . . . . .
- 12.14 DATE fields. . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.15 Changing the record layout.. . . . . . . . . . . . . . . . . .
- 12.16 Member functions in alphabetical order . . . . . . . . . . . .
- 12.17 Warning. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 12.18 Example. . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 13 VRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.2 Creating. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.3 Opening & Closing . . . . . . . . . . . . . . . . . . . . . . .
- 13.4 VRAM Pointers . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.5 Fragmentation . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.6 Root. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 13.7 Functions in Alphabetical order.. . . . . . . . . . . . . . . .
-
- 14 VBASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 14.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 14.2 Using VBASE.. . . . . . . . . . . . . . . . . . . . . . . . . .
- 14.3 Relocating records. . . . . . . . . . . . . . . . . . . . . . .
- 14.4 Limitations.. . . . . . . . . . . . . . . . . . . . . . . . . .
- 14.5 Functions in alphabetical order.. . . . . . . . . . . . . . . .
-
- 15 VBAXE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 15.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 15.2 Working.. . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 15.3 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 15.4 Prototypes. . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 16 CSDIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 17 CSINFO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 18 CSERROR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 19 CSADD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 19.1 Source. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 19.2 Openings screen . . . . . . . . . . . . . . . . . . . . . . . .
- 19.3 Features. . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 20 CSTOOLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 20.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 21 CSKEYS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 21.1 CSKEYS.exe. . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 22 HEAP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 22.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 22.2 When to use it? . . . . . . . . . . . . . . . . . . . . . . . .
- 22.3 Using HEAP. . . . . . . . . . . . . . . . . . . . . . . . . . .
- 22.4 Functions in alphabetical order.. . . . . . . . . . . . . . . .
-
- 23 Alloc-Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 23.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 23.2 Replacements. . . . . . . . . . . . . . . . . . . . . . . . . .
- 23.3 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 23.4 Memory Leaks. . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 24 CSEDSTR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 25 CSWINDOWS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 25.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . .
- 25.2 General Information . . . . . . . . . . . . . . . . . . . . . .
- 25.3 The C++ version, the class WINDOW . . . . . . . . . . . . . . .
- 25.3.1 Syntax of the MEMBER functions. . . . . . . . . . . . . .
- 25.4 The C version . . . . . . . . . . . . . . . . . . . . . . . . .
- 25.4.1 Example . . . . . . . . . . . . . . . . . . . . . . . . .
- 25.5 Syntax of the C functions . . . . . . . . . . . . . . . . . . .
- 25.6 Working within a Window . . . . . . . . . . . . . . . . . . . .
- 25.7 File Browsing . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 26 CSMENU. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 26.1 General Information . . . . . . . . . . . . . . . . . . . . . .
- 26.2 Defining a menu . . . . . . . . . . . . . . . . . . . . . . . .
- 26.3 Connecting menus. . . . . . . . . . . . . . . . . . . . . . . .
- 26.4 Displaying the menu . . . . . . . . . . . . . . . . . . . . . .
- 26.5 Using menus . . . . . . . . . . . . . . . . . . . . . . . . . .
- 26.6 Removing the menu . . . . . . . . . . . . . . . . . . . . . . .
-
- 27 CSPANEL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 27.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 27.2 General Information . . . . . . . . . . . . . . . . . . . . . .
- 27.3 Public member functions . . . . . . . . . . . . . . . . . . . .
- 27.4 Dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 27.5 Fields. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- 27.6 Using the panels. . . . . . . . . . . . . . . . . . . . . . . .
- 27.7 Data validation . . . . . . . . . . . . . . . . . . . . . . . .
- 27.7.1 Min and Max . . . . . . . . . . . . . . . . . . . . . . .
- 27.7.2 Reset Max & Min . . . . . . . . . . . . . . . . . . . . .
- 27.7.3 Templates . . . . . . . . . . . . . . . . . . . . . . . .
-
- 28 Registration Form . . . . . . . . . . . . . . . . . . . . . . . . . .
-
- 2 Preface
-
-
- This is a shareware package consisting mainly of two distinct libraries.
- The libraries are to be used with Borland C++ 3.1 or later. Both
- MS-DOS and Windows applications are supported.
-
- The libraries are intended for programmers who need some kind of
- database in their application but are reluctant to use any of the vast
- DBMS's. The supplied classes are doing all their IO themselves, apart
- from the OS, no other software is needed.
-
- One library concentrates on supplying a user-interface for the non-
- Windows programmer, the other library supplies the classes necessary
- to build database applications. An application generator is used to
- produce the source for the more complicated databases with indexes
- and fields.
-
-
- 2.1 Shareware
-
- This software is distributed as 'Shareware' which means you are free to
- copy and share these files.
- It is a fully functioning version, but it does NOT include the complete
- package.
-
-
- 2.2 Contacting the Author
-
- You can reach me, preferably, by E-mail. The address is:
- T.P.vandenBout@et.tudelft.nl.
-
- If you don't have E-mail access you can reach me by traditional mail:
- Theo van den Bout
- P.O. Box 3303
- 2280 GH Rijswijk
- The Netherlands
-
- For urgent matters only, phone me at +31703960172.
- Please remember, it is GMT +100 over here. I have serious problems
- with being woken in the middle of the night!
-
-
- 2.3 Registering
-
- When you send f 200.- (200 Dutch guilders) or $ 125 (125 American
- Dollars) you will become a 'registered user'.
-
- This means you will receive
- - the latest version
- - all the libraries
- - support.
- - a nice manual.
-
-
- Send money, check or money order to:
-
- Combis
- P.O. Box 3303
- 2280 GH Rijswijk
- The Netherlands
-
- You will find a registration form at the end of this documentation.
- 2.4 Legal Matters
-
- 2.4.1 Disclaimer
-
- EXCEPT WHEN OTHERWISE STATED IN WRITING THE
- COPYRIGHT HOLDER AND/OR OTHER PARTIES PROVIDE THE
- PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
- EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD
- THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO
- EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO
- IN WRITING WILL THE COPYRIGHT HOLDER BE LIABLE TO YOU
- FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
- INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
- THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT
- NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
- INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
- PARTIES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
- 2.4.2 Trademarks
-
- IBM is a registered trademark of International Business Machines
- Corporation.
- MS-DOS and Windows are registered trademarks of Microsoft
- Corporation.
- Borland C/C++ and dBASE are registered trademarks of Borland
- International Inc.
-
-
-
-
-
-
-
-
-
-
-
- Part
-
- One
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The next part of the documentation gives an overview of this
- package.
- It will also discuss the PAGE- and the BUFFER-class from which all
- database classes are derived.
- Some other topics of general interest are covered too.
- 3 Introduction
-
-
- This package mainly consists of two almost independent libraries. The
- library called CSDB, is the far most important one. The other one, CSA,
- is kind-of 'thrown in for free'. Despite this, it contains important general
- purpose functions heavily used by the CSDB library.
-
- The main purpose of this library is to provide a C++ programmer with
- the utilities to incorporate databases in its applications without being
- forced to use one of the huge DBMS's currently on the market. The
- CSDB-library contains the classes needed to fulfil this purpose.
- Therefore, the emphasis in this documentation is on the CSDB library.
-
- The CSA library is intended to provide the non-Windows programmer
- with the tools to easily build a user interface. The library therefore
- contains classes for menu's, forms and windows.
-
- As an example an address-book type of application is included. This
- should give a quick impression of the purpose and capabilities of the
- classes.
-
- Although this package is shareware, it still contains a fully functioning
- version. However, not all the libraries are included. What is shipped is
- the library with the debug-version of the large memory model. As
- explained further on, there are two versions of each library. One
- containing a lot of code to trap errors, and a second one optimized for
- speed.
- The library in this shareware package will therefore produce somewhat
- larger and slower applications then needed. Please, do keep this in
- mind.
-
- 4 Overview
-
- This page will try to give a quick overview of the contents of this
- package.
-
- The CSDB-library contains (among others) the following classes:
- TBASE: A class for reading and wrtiting records.
- BTREE: A btree+ to be used as an index.
- VRAM: A 'database' organized as a heap.
- VBASE: Variable length records.
- VBAXE: As VBASE but for very large databases.
-
- The CSA-library contains general-purpose functions and classes to
- build a character oriented user-interface. Among others, the following
- classes are included:
- WINDOW: Text windows.
- MENU: A menu system.
- PANEL: Data entry screens.
- HEAP: To efficiently allocate many small blocks from the
- heap.
-
- Command line utilities (DOS):
- CSDIR: Lists the databases in a directory.
- CSINFO: Displays information about a database.
- CSDBGEN: Important program-generator.
- CSERROR: Utility to convert the error file to C++ source.
- CSKEYS: Displays the return value of the cskey() function.
- CSMALLOC: Tests the allocation log for memory leaks.
-
- Documentation:
- CSDB.txt: This documentation in ASCII format.
-
- Examples:
- CSADDRESS: A nice address database (DOS).
- CSMENDEM: Demonstration of the MENU class.
- CSPANDEM: Demonstration of the PANEL class.
-
- 5 Debugging
-
-
- Of each library two versions exist, one to be used during debugging
- and one intended for normal 'production'. The difference is that in the
- debug-version a lot more tests are done, and so many more errors are
- reported.
-
- The idea is to use the debug version during development and
- recompile with the production version when ready. The debug version
- is identical to the production version, but with additional tests. The
- 'working code' is 100% identical. This means there are no subtle
- differences between the two versions.
-
- The production version however can be substantial faster, up to two
- times, depending on the circumstances.
-
- To give an example:
- The TBASE class has functions to read a record from the
- database. For this function to operate properly, the class/database
- needs to be 'opened'. In the debug version this is tested with every
- call to the read function. In the production version this is never
- tested. Note that in a decently written and tested application this
- error should not occur. Errors with the open function should be
- trapped much earlier.
-
- There are many more errors like this. Errors that should not occur when
- the application is tested and (almost) ready but which can easily
- emerge in the development stage.
-
- 6 Runtime Libraries
-
- The libraries are to be used with the Borland C++ compilers. Versions
- exist for both MS-DOS and Windows.
-
- With MS-DOS three memory models are supported: compact, large and
- huge. These are the memory models which use far data.
- The same applies for MS-Windows but with the exception of the huge
- memory model. Windows doesn't allow that.
-
- ╔══════════════╤═════════════╤═══════════╤════════════╤════════════════╗
- ║ Name │Operating │ Library │ Memory │ Type ║
- ║ │System │ │ Model │ ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDACP │Dos │ CSA │ Compact │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDACD │Dos │ CSA │ Compact │ Debug ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDALP │Dos │ CSA │ Large │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDALD │Dos │ CSA │ Large │ Debug ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDAHP │Dos │ CSA │ Huge │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDAHD │Dos │ CSA │ Huge │ Debug ║
- ╚══════════════╧═════════════╧═══════════╧════════════╧════════════════╝
-
-
- ╔══════════════╤═════════════╤═══════════╤════════════╤════════════════╗
- ║ Name │Operating │ Library │ Memory │ Type ║
- ║ │System │ │ Model │ ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSWACP │Windows │ CSA │ Compact │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSWACD │Windows │ CSA │ Compact │ Debug ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSWALP │Windows │ CSA │ Large │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSWALD │Windows │ CSA │ Large │ Debug ║
- ╚══════════════╧═════════════╧═══════════╧════════════╧════════════════╝
-
- ╔══════════════╤═════════════╤═══════════╤════════════╤════════════════╗
- ║ Name │Operating │ Library │ Memory │ Type ║
- ║ │System │ │ Model │ ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDCP │Dos │ CSDB │ Compact │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDCD │Dos │ CSDB │ Compact │ Debug ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDLP │Dos │ CSDB │ Large │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDLD │Dos │ CSDB │ Large │ Debug ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDHP │Dos │ CSDB │ Huge │ Production ║
- ╟──────────────┼─────────────┼───────────┼────────────┼────────────────╢
- ║ CSDDHD │Dos │ CSDB │ Huge │ Debug ║
- ╚══════════════╧═════════════╧═══════════╧════════════╧════════════════╝
-
-
- ╔══════════════╤═════════════╤═══════════╤══════════════╤══════════════╗
- ║ Name │Operating │ Library │ Memory │ Type ║
- ║ │System │ │ Model │ ║
- ╟──────────────┼─────────────┼───────────┼──────────────┼──────────────╢
- ║ CSWDCP │Windows │ CSDB │ Compact │ Production ║
- ╟──────────────┼─────────────┼───────────┼──────────────┼──────────────╢
- ║ CSWDCD │Windows │ CSDB │ Compact │ Debug ║
- ╟──────────────┼─────────────┼───────────┼──────────────┼──────────────╢
- ║ CSWDLP │Windows │ CSDB │ Large │ Production ║
- ╟──────────────┼─────────────┼───────────┼──────────────┼──────────────╢
- ║ CSWDLD │Windows │ CSDB │ Large │ Debug ║
- ╚══════════════╧═════════════╧═══════════╧══════════════╧══════════════╝
-
- Of course you have noticed there is a system in these names:
- csOLMT.lib
- with:
- O: Operating System
- D is DOS,
- W is Windows
- L: Library
- A is CSA
- D is CSDB
- M: Memory model
- C is Compact
- L is Large
- H is Huge
- T: Type
- P is Production
- D is Debug
-
- In the shareware distribution only two libraries are found:
- CSD.lib: For Dos. This is a combination of
- CSDDLD.lib and CSDALD.lib.
- CSW.lib: For Windows. This is a combination of
- CSWDLD.lib and CSWALD.lib.
-
-
- 6.1 Using the libraries
-
- Unless you are using only the classes from the CSA collection you
- always have to link in two libraries.
-
- Example:
- Suppose you start developing in the large memory model under
- DOS. Link CSDDLD.lib and CSDALD.lib. It is best to link
- CSDDLD.lib first.
-
- When the application is appropriately debugged, it is time to start
- using the CSDDLP.lib and the CSDALP.lib.
-
- After that, you may consider porting to Windows. Assuming you
- can skip the debugging phase there, link the CSWDLP.lib and the
- CSWALP.lib.
-
- Users of the shareware distribution have far less choice:
- use CSD.lib for DOS and CSW.lib for windows.
-
-
- 6.2 Compiler options
-
- The production library is compiled with:
- - No tests for stack overflow.
- - Optimized for speed.
- - No overlays.
- - 80286 instructions.
- - Signed characters with BC 3.1
- - 'Undefined' characters with BC 4.x.
- - Byte alignment.
-
- The debug library is compiled with tests for stack overflow. Apart from
- that it's identical. (Using the same compiler options that is.)
-
- The Windows' version is compiled with 80386 instructions.
-
- Make sure you are using the right type of characters. If not,
- you will experience linking problems.
- Don't use word-alignment.
-
- 7 General Definitions & Functions
-
-
- 7.1 Portability
-
- A series of typedefs is used to create portable variable types.
-
-
- S8: Singed 8 bit, (singed char)
- U8: Unsigned 8 bit, (unsigned char)
- S16: Singed 16 bit (int)
- U16: Unsigned 16 bit (unsigned int )
- S32: Singed 32 bit (long)
- U32: Unsigned 32 bit (unsigned long)
-
- uchar unsigned char
- schar signed char
- CSCHAR char
-
-
- However, on many occasions (particularly function returns) the range of
- the variable is not all that much important. In these cases integers are
- used because that's normally the fastest.
-
-
- 7.2 Messages and errors
-
- A special set of functions is used to display errors, messages and the
- alike. To avoid confusion: these are 'normal' C-type functions, not
- public functions of some message class.
-
- All these functions eventually display their messages through a call to
- csmess_disp(char *).
- By default (under DOS), this function writes all the messages to the
- console by using the standard cputs() function.
- With WINDOWS, a standard message box is called.
-
- Fortunate, this function can easily be altered.
- Before being displayed by the csmess_disp() function, all the messages
- are converted into a single string. This makes changing the message
- function very easy. Only a single function, which accepts a character
- pointer, needs to be supplied.
-
- The next function is intended to do that:
-
- void csmess_set_fun( void (* fun)(char *));
-
-
- // Example (Dos):
-
- void display(char *s)
- {
- // This function is going to be used
- // To display messages.
- printf("%s",s);
- }
-
-
- void main(void)
- {
- csmess_set_fun(display);
- // From now on, all the messages are
- // displayed through a call to the
- // 'display()' function.
- }
-
-
-
- To restore the default, the next function can be used:
-
- void csmess_reset_fun(void);
-
-
- // Example:
-
- void main(void)
- {
- csmess_reset_fun();
- // Restores the default
- // Display function.
- }
-
-
- void csmess_off(void);
- With this function, messages can be suppressed.
- Whether you are using the standard message
- function or has it replaced with your own, after a call
- to this function no message will be displayed.
-
- void csmess_on(void);
- To be used in conjunction with the csmess_off()
- function. After a call to 'csmess_on()' messages will
- be displayed again.
-
- int csmess_onoff(void);
- Returns TRUE if message displaying is switched on.
- FALSE otherwise.
-
- void csmess_onoff(int sw);
- If called with sw unequal zero, messages will be
- displayed. Otherwise not.
-
-
- 7.3 Temporary Files.
-
- Temporary files are created through the use of the cstmpname()
- function, discussed in the CSTOOLS chapter.
- This means, the environment variables TEMP and TMP are checked to
- determine which subdirectory is going to be used.
- Temporary files can be as large as the databases they are belonging
- to. So, make sure the environment variables don' t point to some small
- ram-disk or an insufficient large partition.
-
- 8 Buffering
-
-
- All the disk IO is done by a very solid buffer-system. All the database
- classes have a function which makes it possible to control the amount
- of memory used for buffering.
-
- This amount is not allocated right from the start but is interpreted as a
- maximum. This means that buffers are allocated on the fly, up to this
- limit. The advantage is that the maximum may never be reached,
- saving valuable memory for other purposes.
- Of course there is also a drawback. The problem is that there is no way
- the classes can predict how much memory needs to be reserved for
- the remaining part of the program. The buffering-system itself will stop
- allocating memory when the heap is exhausted, but if dynamic memory
- allocation is used somewhere further on, the program may still
- terminate with a message of the type 'out of memory'.
-
- It should be noted that this is only a problem with the MS-DOS
- operating system. Any other (real) operating system uses virtual
- memory which makes sure that your program will work with any
- reasonable assumption about the available amount of memory. For
- performance reasons, however, it is better not to rely on virtual
- memory. Let the classes do the buffering, not the operating system.
-
- What all this means is that with MS-DOS you have to be
- careful about using a large amount of ram for buffering.
-
-
- 9 PAGE-Class
-
- 9.1 Introduction
-
- The PAGE-class constitutes a kind of 'foundation' for most of the
- other classes in the CSDB library. It is derived from a class 'BUFF'
- which takes care of the required buffering. (Described in the previous
- chapter.)
-
- The idea is to do disk IO in chunks of 2 Kb. This is close to the optimal
- size for the average harddisk. These blocks are kept aligned with the
- sectors of the harddisk, which improves speed considerablely.
- A harddisk always reads an entire sector, even if you only need, let's
- say, 10 bytes. Things become even worse if the 10 bytes you are
- requesting just happen to cross a sector boundary. In that case your
- harddisk will read 2 entire sectors. Assuming a sector is 1024 bytes,
- this means that 2*1024=2048 bytes are read just to obtain your 10
- bytes!
-
- To avoid this kind of inefficiency the PAGE-class does its disk IO in
- pages of 2048 bytes while making sure every page is aligned with the
- harddisk sectors. This also means that the indispensable file-header
- has to be at least one sector. To avoid complications, a file-header is
- used which has the same size as a page, 2048 bytes by default.
-
- It should be noted that this entire scene is undone by using a
- disk compression utility, like double space, stacker and the
- alike.
-
- Therefore, if you are concerned about performance, it is better not to
- use these utilities. More over, a disk compressor will slow down your
- application considerablely when several files are used heavily 'at the
- same time'. This situation will almost inevitably arise with any serious
- application which uses more then one database, or even a single
- database with many indexes.
-
-
- 9.2 Background
-
- One of the special features implemented in the PAGE-class is the
- 'background()' function.
- This function is intended to make good use of the idle time waiting for
- the user's input. It is guaranteed to return in a very short period of time,
- doing at most one disk IO with every call.
-
-
- By result you can write code like:
-
- while(!kbhit()) CLASS.background();
-
-
- E.g. the background() function supplied by the PAGE class writes 'dirty'
- buffers back to disk. This is done one-by-one. Each call will write at
- most one buffer. Because of this, the application user will hardly notice
- anything, while in the future the application doesn't have to spend time
- writing buffers back to disk.
-
- The function will return a value greater then zero if something has been
- done and zero otherwise.
- After some time the class runs out of things to do and it becomes
- pointless to spend CPU-time on calls to the background() function. By
- testing the return value, this can be avoided.
-
- In some derived classes, the background() function is overloaded to do
- additional house keeping.
-
-
- 9.3 Storing data in the header-page
-
- As explained above, the header page is quite large. This page is used
- to store al kind of important variables. However, there is still much
- space left. Of the 2048 bytes only about 170 are used.
-
- An application using databases is like to have some variables of his
- own which need to be maintained between close/open sequences. It
- seems the remaining space in the header page is a convenient place
- store such data. This can save you an additional configuration file and
- all the error trapping involved.
-
- To aid in this, three functions are made public:
- int data_2_header(void * ptr,U16 length);
- int header_2_data(void * ptr,U16 length);
- U16 max_data_in_header(void);
-
- U16 max_data_in_header(void);
- This function returns the maximum number of bytes
- which will still fit in the header page. This is simply
- the size of the header-page minus what is used to
- store the variables of the class.
- The class needs to be open.
-
- int data_2_header(void * buffer,U16 length);
- Copies data from buffer 'buffer' to the empty space in
- the header page. The variable 'length' indicates the
- number of bytes to be copied. This figure is not
- stored anywhere. It is the programmers' responsibility
- to retrieve the right number of bytes later on.
- The class needs to be open.
-
- int header_2_data(void * buffer,U16 length);
- The counterpart of the previous function. This
- function copies 'length' number of bytes from the
- header page to 'buffer'.
- The class needs to be open.
-
-
-
-
-
-
-
-
-
- Part
-
- Two
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Part Two of the documentation will explain how this library can be
- used to build traditional relational databases.
- To do so, it uses a TBASE class to store records and a BTREE
- class for indexes.
- A program generator, CSDBGEN, is discussed which 'automates'
- the process of building more complex databases out of TBASE and
- BTREE.
- These two classes can also be used seperately. In particular the
- BTREE class is very useful. It is really easy expandable and can be
- tailored to a specific purpose by supplying one single function.
- Simple databases with only one index can be build with just the
- BTREE class.
-
-
- 10 TBASE-class
-
-
- 10.1 Introduction
-
- The TBASE class is intended as a simple, fast way to access records
- on disk. It assumes a fixed record size and does its IO on a record-by-
- record basis (contrary to field-by-field).
-
- This means:
- 1) TBASE is unaware of something like 'fields'. The idea is to use
- a C structure as record and to do all the accessing of fields
- with the standard C operators. This approach is undoubtedly
- faster then supporting access on a field-by-field basis as done
- by dBASE.
- 2) No indexes. TBASE just reads or writes records, nothing else.
-
- NOTE: From this it is clear that with the TBASE class alone no decent
- database application can be build. Therefore, a separate
- BTREE class is supplied which can be used as an index.
- To glue it all together, a program generator, CSDBGEN, is
- available. Because C isn't particularly bright in handling strings
- and date's, the program generator takes care of that too.
-
-
- 10.2 Using TBASE
-
- The next small example gives an impression of how to use the class.
-
- As can be seen from this example, there is no 'record pointer' as in
- dBASE. The functions to read and write a record, simply take an
- additional parameter indicating the record number.
-
-
-
- // A very simple example.
-
- # include "CSTBASE.H"
-
- void main(void)
- {
- typedef struct
- {
- char name[20]; // The field 'name'
- char street[40]; // The field 'street'
- long salary; // The field 'salary'
- // All the other fields you may require.
- }record; // The record layout is now defined.
-
- TBASE db;
- record rec;
- db.open("demo.dbf",110); // Assuming the file is already created.
- // Use 110 kB for buffering.
- db.read_rec(9,&rec); // Read record number 9 into
- // variable 'rec'.
- rec.salary=0; // Change salary.
- db.write_rec(9,&rec); // Write the record back to position 9.
- // (Any other position is also possible.)
- db.close(); // Is also done automatically
- // by the class destructor.
- }
-
-
-
-
-
- 10.3 Creating a Database
-
- Before a database can be used it has to be 'created'. This is done
- through a call to the 'define()' function. Of course this is needed only
- once.
- Because TBASE doesn't use fields, the function takes only two
- parameters: the filename of the database, and the record size.
-
- Syntax: int define(char * name,U16 reclen);
-
-
- // This example creates a database 'demo.dbf'.
-
-
- #include "CSTBASE.H"
- void main(void)
- {
- typedef struct
- {
- char name[20];
- char street[40];
- char city[25];
- } record;
-
- TBASE db;
- db.define("demo.dbf",sizeof(record));
- }
-
-
-
- 10.4 Opening
-
- Before a record can be read, the database has to be opened through a
- call to the open() function.
-
- This open() function also takes a parameter indicating the amount of
- memory to be used for buffering. The memory for the buffers is NOT
- allocated at the moment of the call to open(), but during the use of the
- database. Memory is allocated when needed, up to this maximum.
-
- As explained in the chapter about buffering, using up too
- much memory for buffering is dangerous on an Operating
- System like MS-DOS with no virtual memory.
-
- Syntax: int open(char *name, S16 kb=32);
-
-
- // Example:
- // Opening the existing database 'demo.dbf' with 40 kB for buffers.
-
- #include "CSTBASE.H"
- void main(void)
- {
- TBASE db;
- db.open("demo.dbf",40);
- }
-
-
-
- 10.5 Closing
-
- Closing the database involves writing all the buffered data back to disk
- and freeing all allocated memory. The close() function is intended for
- this purpose. If the close() function is not explicitly called in the
- application, the class destructor will call it.
-
- Because there can be a long interval between the last time the
- database is used and the moment where the destructor is reached, it
- still makes sense to call the close() function 'by hand'.
-
- Syntax: int close(void);
-
-
- // Example:
-
- #include "CSTBASE.H"
- void main(void)
- {
- TBASE db;
- db.open("demo.dbf",40);
- db.close();
- }
-
-
-
- 10.6 Appending Records
-
- A special function is needed to add a record to a database: the
- append_rec() function.
- Note: The write_rec() can only overwrite an already existing record.
-
- Syntax: long append_rec(void *data);
- 'data' is a pointer to a record.
-
- Syntax: long append_rec(void);
- This function can be used to add a record to the
- database without instantly filling it with a record. For
- the time being, this record will contain 'garbage'.
-
- // Example:
-
- #include "CSTBASE.H"
- void main(void)
- {
- typedef struct
- {
- char name[20];
- char street[40];
- char city[25];
- } record;
-
- TBASE db;
- record rec;
-
- db.define("demo.dbf",sizeof(record)); //Create new database
-
- db.open("demo.dbf",40);
-
- strcpy(rec.name,"J.Q. Querlis ");
- strcpy(rec.street,"Avenue 120");
- strcpy(rec.city,"Bombay");
-
- db.append_rec(&rec); // The database now contains 1 record.
- db.close();
- }
-
-
-
- 10.7 Deleting Records
-
- Deleting a record cannot be accomplished instantaneously. A 'delete
- bit' is used to distinguish deleted records.
-
- Deleting a record by setting the 'delete bit' doesn't alter much. E.g.
- record 9 remains record 9 if you delete record 8.
- The function 'is_delet()' has to be called to detect whether-or-not a
- record is 'deleted'.
-
- The 'pack()' function can be used to physically remove all the deleted
- records from the file.
-
- int is_delet(long r);
- Returns 0 if the record 'r' is not deleted, and 1
- otherwise.
-
- void delet(long r);
- Sets the delete bit for record 'r'.
-
- void undelet(long r );
- Resets the delete bit for record 'r'.
-
- void pack(void);
- Removes all the records with the delete bit set from
- the database. This is done without the use of
- temporary files.
-
-
- 10.8 Advanced Topics
-
- The next paragraph can be skipped by first-time readers.
-
- 10.8.1 Page Utilization
- The TBASE class does its IO in pages of 2 kB. It fits an integer number
- of records on these pages. This approach can lead to a large chunk of
- unused space on the pages, particularly if you are using large records.
- On average the slack will be a half record, but if you have a record of
- 1100 bytes almost 1 kB will be wasted!
-
- Solution:
- This waste of disk space can be avoided by using pages which
- have the same size as the record. This means that the pages will
- no longer be aligned with the sectors of your harddisk!
-
- The function to accomplish this is: smallest_page().
-
- void smallest_page(void);
- The function has to be called before the define()
- function. Because this changes the entire layout of
- the database file, this cannot be altered once the
- database is created.
-
-
- // Example:
-
- #include "CSTBASE.H"
-
- void main(void)
- {
-
- typedef struct
- {
- char name[20];
- char street[40];
- char city[25];
- } record;
-
- TBASE db;
-
- db.smallest_page(); //Before the define!
-
- db.define("demo.dbf",sizeof(record));
-
- }
-
-
-
- 10.8.2 Locating Records
- In the examples given so far, a record is first read into a local variable
- and, after being altered, written back to disk. It seems there is room for
- improvement here. After the record is copied into the local variable it is
- in memory TWICE, once in the variable and another time in the
- database buffers.
-
- If you know what you are doing, a significant performance increase
- can be gained from obtaining a pointer directly into the buffer system.
-
- The 'locate_rec()' function does just that. When you are working in the
- database buffers through a pointer, there is no way the buffer system
- can tell if you are altering anything. Therefore, it's the programmers'
- responsibility to indicate whether or not modifications are going to take
- place.
-
- char *locate_rec(long rec);
- This function returns a pointer to record 'rec'. It
- assumes that no alterations are going to take place.
- This means that the buffer is not written back to disk!
-
- char *locate_rec_d(long rec);
- The additional '_d' stands for Dirty buffer. The
- function returns a pointer to record 'rec'. It is
- assumed alterations ARE going to take place. The
- buffer is therefore written back to disk when space is
- needed to store another page.
-
-
- IMPORTANT!!
- The locate functions return a pointer directly into the buffer
- system. Nothing less and nothing more. Any member function
- of the same class instance which MAY cause disk IO, can
- therefore alter the contents of the buffers, making your pointer 'point' to
- an entirely different record! When using these functions, it is highly
- advisable to do all the reading or writing to the record before calling
- any other TBASE member function.
- Special care should be taken in using the 'background()' function.
-
- If you are not sure you fully understand this, don't use the locate
- functions.
-
-
-
-
-
- // Example, of the locate_ function.
-
- #include "CSTBASE.H"
-
- void main(void)
- {
-
- typedef struct
- {
- char name[20];
- int age;
- } record;
-
- TBASE db;
- record *rec;
-
- db.define("demo.dbf",sizeof(record));
- db.open("demo.dbf"); // Use default 32 kB for buffers.
-
- for(int i=1;i<=12;i++) db.append_rec(); // Append 12 records.
-
- rec=(record *)db.locate_rec_d(7); // Obtain pointer to record 7.
- // '_d' because we will 'write'.
-
- rec->age=34; // That's all it takes to make an
- // alteration. No need for a
- // 'write' function.
- db.close(); // Not strictly necessary.
-
- }
-
-
-
- 10.9 Miscellaneous functions
-
- long numrec(void);
- Returns the number of records currently in the
- database.
-
- U16 lengthrec(void);
- The size of the record in bytes.
-
- 10.10 Functions in alphabetical order.
-
- Function prototypes are in 'cstbase.h'.
-
-
- S32 append_rec(void *data);
- Append a record to the database. The newly created
- record is filled with the data from buffer 'data'. The
- function returns the number of the new record (which
- is equal to the number of records in the database).
- S32 append_rec(void);
- Same as the previous function, only this time the new
- record is filled with binary zero's.
- int close(void); Closes the database. If the database is already
- closed, nothing happens. TRUE is returned on
- success, FALSE otherwise.
- int define(char *name,U16 reclen);
- Creates a TBASE file named 'name'. The parameter
- 'reclen' indicates the size of the records. TRUE is
- returned on success, FALSE otherwise.
- void delet(S32 rec);
- Sets the delete bit of record 'rec'.
- int empty(void); Removes all the records from the database.
- Afterwards there will be zero records left, but the
- database will still be open. TRUE is returned on
- success, FALSE otherwise.
- int is_delet(S32 rec);
- Returns the value of the delete bit of record 'rec'.
- TRUE means the delete bit is set, FALSE means the
- bit is not set.
- U16 lengthrec(void);
- Returns the length of a record. Because TBASE
- works with fixed length records, this value is the
- same for all records. It's the same value used in the
- call to define().
- char *locate_rec(S32 rec);
- char *locate_rec_d(S32 rec);
- Functions to return a pointer to record 'rec' directly
- into the buffer system. Please read the paragraph
- about this topic before using these functions.
- S32 numrec(void);
- Returns the number of records currently in the
- database. Whether or not a record is marked for
- deletion makes no difference.
- int open(char *name,S16 kb=32);
- Opens the existing database 'name' while using 'kb'
- Kb ram for buffering. TRUE is returned on success,
- FALSE otherwise.
- int open(void); Returns TRUE if the database is open, FALSE
- otherwise.
- int pack(void); Removes all the records with the delete bit set from
- the database. This is doen without the use of
- temporary files. TRUE is returned on success, FALSE
- otherwise.
- void read_rec(S32 rec, void *buff);
- Copies the contents of record 'rec' into buffer 'buff'.
- int save(void); Writes all buffered data back to disk. The database
- header block is also updated. The database remains
- open. TRUE is returned on success, FALSE
- otherwise.
- void set_delet(S32 rec,int ToF);
- Changes the value of the delet bit of record 'rec'. If
- 'ToF' is TRUE, the delete bit is set, otherwise it is
- reset.
- void smallest_page(void);
- Set the page size to its smallest possible value. That
- is, a page will have the same size as a record. This
- means pages will no longer be alligned with the
- harddisk sectors. The function has to be called before
- the define() function. It changes the entire layout of
- the database file so it cannot be changed once the
- file is created.
- void undelet(S32 rec);
- Resets the delete bit of record 'rec'.
- void write_rec(S32 rec, void *buff);
- Overwrites the contents of record 'rec' the data from
- buffer 'buff'. Record 'rec' needs to exist, the function
- connot be used to append a record.
-
-
- 11 BTREE-class
-
-
- 11.1 Introduction
-
- A btree is a system, developed several decades ago, to store data in
- some predetermined order. The btree is capable of maintaining this
- order even under insertions and deletions.
- It is possible to use btrees for data in ram, but they were designed (and
- so optimized) to work with data on disk. Btrees are capable of locating,
- inserting or deleting a specific record with only a few disk-IOs, even
- when they have become very big.
-
- Of course there is a price to be payed for this: the disk space occupied
- by the btree is not fully utilized. Worst case, only 50% of the space is
- used. Fortunate, in the average case 75% is used.
-
- Btrees are convenient for indexes on a database. Of a record in the
- main database, the key field and the corresponding record number are
- stored together in the btree.
- When a certain record is needed, the btree is capable of quickly
- (without much disk IO) locating the required key value because the
- btree keeps the key values sorted. When the key field is located in the
- btree, it is instantly clear which record from the main database has to
- be read from disk.
-
- There are several 'flavours' of btrees. The one implemented in this
- library is known as a 'btree+'.
-
-
- 11.2 BTREEx Classes
-
- Unfortunate, it's a little cumbersome to use one BTREE class for every
- type of data. Therefore, there are several minor variations on the main
- BTREE class to account for the different variable types supported by C.
- Each type has its own class.
-
- Classes:
- BTREEb For binary data.
- BTREEi For integers.
- BTREEl For longs.
- BTREEc For characters.
- BTREEf For floats.
- BTREEd For doubles.
- BTREEa For ASCII data. (Strings)
-
- All these classes are derived from the BTREE class. Mainly, they differ
- only in one function. This is the function needed to compare keys. You
- can easily define a new BTREE class for new type of variable. The only
- thing to do is define a int t_key(void *a,void *b) function which returns:
-
- >0 if a>b
- 0 if a==b
- <0 if a<b
-
- with 'a' and 'b' pointers to the new type of variables.
-
-
- Example:
- Say, you have your data stored in a C structure which
- you want to kept sorted on one of its fields.
-
- Something like:
-
- typedef struct
- {
- char name[20];
- int number;
- }
-
- Which you want to have sorted on the 'number' field.
-
- class BTREEnew: public BTREE
- {
-
- virtual int t_key(void *a,void *b)
- {
- return ((record *)a)->number-((record *)b)->number;
- }
- virtual int class_ID(void) { return -100; }
- };
-
-
- That's all!
- The value '-100' in the class_ID() function is not all that important. Its
- purpose is to give other library functions the opportunity to distinguish
- between the classes. The value just has to be different from any value
- the other classes have. This can easily be accomplished by choosing a
- negative number.
-
-
- 11.3 Multiple Keys
-
- Because of its nature you would expect a 'key' to appear only once in a
- btree. However, on many occasions it turns out there is a need for
- storing the same key more then once, but with a different data part.
- E.g. this happens when you use a btree as an index on a database and
- in the field you are indexing a certain value appears more then once.
- In that case, you want to store the key value several times but with a
- different data part, namely the record number in the database.
-
- By default a key value can appear only once in the btree. If you try to
- insert a second entry with the same key value, it will simply replace the
- existing one. The option 'multiple_keys()' can be set to alter all that.
-
- Syntax: void multiple_keys(int YesNo);
- void multiple_keys_YES(void);
- void multiple_keys_NO(void);
-
-
- When the function 'multiple_keys()' is called with the argument set to
- TRUE, the btree will store a key value more then once.
-
- It is important to realize that the btree only keeps the key
- values sorted, NOT the data values. This means that when
- you are searching for a particular key/data value, the btree is
- capable of quickly locating the required key but has to find the correct
- data value by sequentially traversing all the inserted data belonging to
- that particular key.
-
- Btrees are intended to give quick access to key values by keeping
- them sorted, this does not apply to data values. Expecting anything
- else is misusing the btree. If you want quick access to a large number
- of different data values, all belonging to the same key, you need a
- different approach. The best thing to do is to construct a new btree and
- use a key which is a concatenation of the original key and the original
- data part.
-
- Setting the multiple_keys option has to take place before the 'define'.
-
-
- // Example
-
- #include "csbtree.h"
-
- void main(void)
- {
-
- typedef struct
- {
- char name[20];
- int age;
- } record;
-
- BTREE bt;
-
- bt.multiple_keys_YES(); // Must be called before 'define'
- bt.define("btree.dat",sizeof(record),sizeof(long));
-
- // By now a btree 'btree.dat' is created in the current working
- // directory with the multiple-keys option switched on.
-
- }
-
-
-
-
- 11.4 Current Pointer
-
- Contrary to TBASE, the btree class does use a 'current' pointer. When
- using btrees, the need to obtain the next (or previous) entry arises so
- often it's inevitable.
-
- The btree class spends as little time as possible on maintaining this
- current pointer. Therefore you should assume it is NOT set, unless you
- have strong reasons to believe otherwise.
-
- A limited set of functions can be used to set the current pointer. After
- that, the 'next()' and the 'previous()' functions can be used to move to
- the next resp. the previous entry.
- When these functions 'fail', which can be noticed from their return
- value, you should assume the current pointer is not set (any more).
-
- The next functions can be used to set the current pointer:
- - all the search functions.
- E.g. search_gt(), find() etc.
- - all the min() and max() functions.
- E.g. max_key(), min() etc.
- - the insert() function.
-
- The current pointer can be moved back and forth with the next() and
- previous() functions.
-
- Once the current pointer is set, the 'current()' functions can be used to
- obtain the key value and/or the data part.
-
- Any other function can, and probably will, render the value
- of the current pointer undefined!
-
-
-
- // Example
- // The next example displays the contents of a btree with
- // 'strings' as key fields.
- // It assumes that the btree 'demo.dbf' exists and that the
- // key fields are less then 100 bytes.
-
- #include "iostream.h"
- #include "csbtree.h"
-
- void main(void)
- {
- char buffer[100];
- BTREEa bt;
-
- bt.open("demo.dbf",250); // Does not set the current pointer.
-
- // Make the first entry the 'current'.
- if(bt.min()) // This returns FALSE only if the btree is empty.
- do
- {
- bt.current_key(buffer); // Read the 'current' key value.
- cout<<buffer<<endl; // Display it.
- } while(bt.next()); // Move the current pointer 1 position.
-
- bt.close();
- }
-
-
-
- 11.5 Using Btrees
-
- The next paragraph will try to sort the public memeber functions
- according to their purpose.
-
- 11.5.1 Creating
-
- void multiple_keys_YES(void);
- void define(char *name,int key_length, int data_length);
-
- 11.5.2 Opening
-
- int open(char *name, int kb_buffer);
-
- 11.5.3 Inserting
-
- void insert(void *key,void *data);
-
- 11.5.4 Searching
-
- int search(void *key,void *Data);
- int search_gt(void *key,void *Key,void *Data);
- int search_ge(void *key,void *Key,void *Data);
- int search_lt(void *key,void *Key,void *Data);
- int search_le(void *key,void *Key,void *Data);
- int search_dat_..(void *key,void *Data);
- int search_key_..(void *key,void *Key);
- int find(void *key,void *data);
- int find(void *key);
- int max(void *Key,void *Data);
- int min(void *Key,void *Data);
-
- 11.5.5 Current
-
- int current(void *Key,void *Data);
- int current_key(void *Key);
- int current_dat(void *Data);
-
- 11.5.6 Deleting
-
- int delet(void *delete_key);
- int delet(void *delete_key,void *data_value);
-
- 11.5.7 Closing
-
- void close(void);
- 11.6 Functions in alphabetical order.
-
- The function prototypes are in "CSBTREE.H".
-
- void close(void);
- Closes the btree after use. All buffers are flushed and
- all the allocated memory is freed. This function is also
- called by the class destructor if needed.
- int current(void *Key,void *Data);
- int current_key(void *Key);
- int current_dat(void *Data);
- Returns the key and/or data part of the entry the
- current pointer is pointing at.
- Parameters:
- Key Pointer to the buffer to which the key value
- has to be copied.
- Data Pointer to the buffer to which the data part
- has to be copied.
- If the current pointer has not been set, the functions
- return FALSE and no data is written into the buffers.
- If the current pointer is set, the functions return TRUE
- and the appropriate data is copied into the buffers.
- void define(char *name, int key_length,int dat_length);
- This function is needed to initially create the file and
- properly setup all variables. This is only needed once,
- before the first call to open().
- Parameters:
- name The filename which is going to be used.
- key_length The number of bytes in the key. This
- parameter is even needed when its
- value is 'obvious' from the btree type.
- dat_length The number of bytes in the data part.
-
- Example:
-
- If you want to use a btree as index on a string field
- in a database you will need:
- - a btree of type ASCII: BTREEa.
- - a key_length equal to the length of the string field
- in the database record.
- - a data part which is capable of holding the number
- of the record in the database. This will normally be
- a 'long'.
-
- #include "cstbase.h"
- #include "csbtree.h"
-
- void main(void)
- {
- typedef struct
- {
- char name[30];
- float income;
- }record;
-
- TBASE db;
- BTREEa index;
-
- db.define("demo.dbf",sizeof(record));
- index.define("demo.ndx",30,sizeof(long));
-
- }
-
-
-
- int delet(void *delete_key);
- Searches for key 'delete_key' and, if present,
- removes it from the btree. If the option multiple_keys
- is set to 'yes' there can be more then one entry with
- the required key. Under that circumstances, all these
- entries will be removed. The function delet() can also
- accept a parameter with the value of the data part.
- That function should be used for deleting when
- multiple keys are used.
- The function returns TRUE is something is deleted,
- FALSE otherwise.
- int delet(void *delete_key,void *data_value);
- The same as the previous delete function but this
- time the value of the data part is also specified. Only
- the entry which matches both the key and the data
- part is removed from the btree.
- void empty(void);
- Removes all the entries in the btree. Upon return, the
- btree will contain zero keys.
- The btree needs to be open, and will remain open
- afterwards.
- int find(void *key,void *data);
- int find(void *key);
- These functions 'test' if a certain key value is present
- in the btree. When a btree is used with multiple keys,
- it can be necessary to specify the data part to
- uniquely identify an entry.
- TRUE is returned when the required entry is found,
- FALSE otherwise.
- void insert(void *key,void *data);
- Inserts a new entry in the btree. 'key' is a pointer to
- the key field and 'data' is a pointer to the data part.
-
-
- // Example:
-
- void main(void)
- {
-
- typedef struct
- {
- char name[30];
- float income;
- }record;
-
- TBASE db;
- BTREEa index;
-
- db.define("demo.dbf",sizeof(record)); //Creating.
- index.define("demo.ndx",30,sizeof(long)); //Creating.
-
- db.open("demo.dbf",30); // Opening the database with 30 Kb buffers
- index.open("demo.ndx",80); // Opening the index with 80 Kb buffers.
-
- record rec;
-
- strcpy(rec.name,"John Wayne");
- rec.income=7000; // Filling the record.
-
- long recnr=db.append_rec(&rec); // Insert in the database.
- index.insert(rec.name,&recnr); // Update the index.
-
- db.close(); // Close the database.
- index.close(); // Close the index.
-
- }
-
-
- int max(void *Key,void *Data);
- int max_dat(void *Data);
- int max_key(void *Key);
- int max(void);
- These functions return the last (highest) entry in the
- btree. The parameters 'Key' and 'Data' have to be
- pointers to respectively a buffer for the key part and a
- buffer for the data part. These buffers will be filled
- with the appropriate data upon function return.
- The functions max_dat() and max_key() can be used
- when only one of the two parts is required.
- TRUE is returned on success, FALSE otherwise.
- int min(void *Key,void *Data);
- int min_dat(void *Data);
- int min_key(void *Key);
- int min(void);
- These functions return the first (lowest) entry in the
- btree. The parameters 'Key' and 'Data' have to be
- pointers to respectively a buffer for the key part and a
- buffer for the data part. These buffers will be filled
- with the appropriate data upon function return.
- The functions min_dat() and min_key() can be used
- when just one of the two parts is required.
- TRUE is returned on success, FALSE otherwise.
- void multiple_keys(int TrueOrFalse);
- With this function the use of multiple keys is
- controlled. For more information about multiple keys
- please read the paragraph about the subject.
- Multiple_keys(TRUE) will allow for multiple keys.
- Multiple_keys(FALSE) will not allow for multiple keys.
- Important:
- This function has to be called before the define()
- function is invoked. It is not possible to alter the
- setting of the multiple key parameter later on.
- int multiple_keys_YES(void);
- Same as multiple_keys(TRUE);
- int multiple_keys_NO(void);
- Same as multiple_keys(FALSE);
- int multiple_keys(void);
- This function returns TRUE if multiple keys is set to
- 'YES' and FALSE otherwise.
- int next(int n);
- int next_key(int n,void *Key);
- int next_dat(int n,void *Data);
- int next(int n,void *Key,void *Data);
- A set of functions to move the current pointer closer
- to the 'end' of the btree.
- Apart from that, they are similar to the prev() funtions.
- For more information, please see over there.
- int next(void);
- Same as next(1); but more efficient.
- long numkey(void);
- This function returns the number of entries which
- exists in the btree.
- int open(char *name, int kb_buff);
- Opens an existing btree 'name'. The parameter
- 'kb_buff' indicates how many Kb ram has to be used
- for buffering.
- The function returns TRUE on success, FALSE
- otherwise.
-
- //Example:
-
- #include "csbtree.h"
-
- void main(void)
- {
-
- BTREEa index;
- index.open("demo.ndx",100);
-
- }
-
- This will open the btree 'demo.ndx' and will, at most,
- use 100 Kb ram for buffering.
- NOTE: read the chapter about buffering, before
- using really large amounts of buffers.
- void pack(void);
- A function which optimizes disk usage. Due to many
- insertions and deletions it is possible for blocks with
- zero keys to emerge. There are no pointers to these
- blocks but they will still be part of the btree because
- they can not be removed unless they are the last
- block in the file. These blocks will be used as soon
- as the need for a new block arises.
- The pack function will remove these empty blocks
- and rearrange all the keys. This is done by writing all
- the data to a temporary file and reload the btree.
- Afterwards the btree will be (close to) 100% full.
- int prev(void);
- int prev(int n);
- int prev_key(int n,void *Key);
- int prev_dat(int n,void *Data);
- int prev(int n,void *Key,void *Data);
- A set of functions to move the current pointer closer
- to the 'beginning' of the btree.
- Parameters:
- n The number of entries the current pointer
- needs to be moved.
- Key A pointer to the buffer which is going to be
- filled with the value of the key field.
- Data A pointer to the buffer which is going to be
- filled with the value of the data part.
- When the current pointer is NOT moved, the key and
- data buffers will not be filled. Otherwise they will be
- filled with the values of the entry to which the current
- pointer is moved.
- The key field, the data field, or both can be obtained
- by selecting the appropriate function.
- The prev(void) function is a much more efficient
- version of the prev(1) function.
- Important:
- This current pointer needs to be set first. Please,
- read the praragraph about the 'current pointer' for
- more information.
- When one of the prev() functions is called while the
- current pointer is not set, the function will return 0.
- This current pointer can not be moved before the
- beginning of the btree. Therefore the number of
- positions moved can differ from the number
- requested.
- The return value is the number of positions the
- current pointer has actually moved.
- int search(void *key,void *Data);
- Searches for 'key' and fills buffer 'Data' with the
- corresponding data part if 'key' is found.
- The function returns TRUE if found, FALSE
- otherwise.
- int search_gt(void *key,void *Key,void *Data);
- int search_ge(void *key,void *Key,void *Data);
- int search_lt(void *key,void *Key,void *Data);
- int search_le(void *key,void *Key,void *Data);
- The purpose of this set of functions is to search for a
- key value next to a given value. The names of the
- output parameters start with a capital while the input
- parameters are all lower case.
- The suffix '_xx' has a meaning conform to the
- corresponding FORTRAN operators:
- gt: Greater Then >
- ge: Greater Equal >=
- lt: Less Then <
- le: Less Equal <=
- The functions return TRUE if such a key could be
- found, FALSE if not.
-
- Example:
- Assume the next table represents a btree.
-
- Entry Key value Data value
-
- 1 Blue 123
- 2 Green 45
- 3 Red 678
-
- search_gt("Blue",Key,Data)
- Return value: TRUE
- Key: Green
- Data: 45
-
- search_ge("Blue",Key,Data)
- Return value: TRUE
- Key: Blue
- Data: 123
-
- search_lt("Blue",Key,Data)
- Return value: FALSE
- Key: undefined
- Data: undefined
-
- search_ge("Orange",Key,Data)
- Return value: TRUE
- Key: Red
- Data: 678
-
-
- int search_dat_..(void *key,void *Data);
- int search_key_..(void *key,void *Key);
- The previous described functions return both the key
- value and the data value.
- In some cases this will be a waste of memory,
- therefore there are two similar sets of functions,
- which either return the found key value or the data
- part.
- search_dat_..() returns only the found data value.
- search_key_..() returns only the found key value.
-
- Example:
-
- With the same btree as in the previous example
-
-
- search_dat_gt("Blue",Data)
- Return value: TRUE
- Data: 45
-
- search_key_ge("Blue",Key)
- Return value: TRUE
- Key: Blue
-
-
- int skip(int n);
- int skip(int n,void *Key,void *Data);
- int skip_key(int n,void *Key);
- int skip_dat(int n,void *Dat);
- A set of functions to move the current pointer. These
- functions are front ends for the next() and prev()
- functions. E.g. this is how the skip_key() function is
- implemented:
-
-
- int skip_key(int n,void *Key)
- { if(n>0) return next_key( n,Key);
- else return -prev_key(-n,Key); }
-
-
- So, with these functions the argument 'n' may be
- positive or negative.
- With 'n' positive the current pointer is moved to the
- 'end' of the btree. This is done by calling next(n).
- With 'n' negative the current pointer is moved to the
- 'beginning' of the btree. This is done by calling
- -prev(-n).
- The return value can be either positive or negative
- depending on the value of 'n'. When 0 is returned, the
- current pointer has not been moved or was not set.
- See also the prev() functions for more information.
- void zap(void);
- Closes the btree (when needed) and re-establishes
- all defaults. In other words: the zap() function
- restores the status of the btree immediatly after the
- class constructor. Its purpose is to open (or create) a
- new btree, starting of with all the parameters set to
- their default values.
- 12 CSDBGEN
-
-
- 12.1 Introduction
-
- CSDBGEN is a program generator.
-
- So far we have discussed the TBASE class which is capable of reading
- and writing records and the BTREE class which can be used as an
- index. CSDBGEN is needed to make a nice database out of this, which
- is capable of manipulating fields, maintaining indexes and the alike.
-
- It takes as input a 'definition file' which describes the fields and the
- indexes. From this it produces the source for a new C++ class. Member
- functions of this newly created class are used to access the fields.
-
- CSDBGEN does not generate a user-interface.
-
- There are several good reasons for using a program generator.
- - The TBASE class can concentrate on manipulating records rather
- then fields. Because of that, it remains a universal and efficient
- way to do disk IO.
- - With this approach it is easier to deal with field types that are not
- supported by the C programming language, particularly dates.
- - It is relatively easy for the program generator to convert to dBASE
- format because it has all the required knowledge at hand. Figuring
- out this conversion during runtime is a lot more complicated and
- will also make your executable larger because the knowledge to do
- the conversion is in the application instead of in the program
- generator.
- - Or more in general: everything the program generator does, can be
- left out from the application, making the executable smaller.
- - Without a program generator, the differences between the field types
- have to be dealt with runtime, perhaps even with every call
- accessing a field. Doing so, will inevitable result in some sort of an
- interpreter. Interpreters have two major drawbacks. First they are
- amazingly slow, and second they contain functions to handle every
- possible case. This means code is linked in for every known field
- type, even if it's not used.
-
- 12.2 Overview
-
- Using CSDBGEN starts of with creating a definition file. This file
- describes the layout of a record, the indexes, the name of the new
- class and the name of the files.
-
- When this file is created, CSDBGEN is called with this filename as a
- parameter. In return you will obtain the source for a brand new C++
- class. This source is ready to compile, without the need for manual
- editing.
-
- This new class has public member functions for things like reading a
- field, setting the active index, exporting to ASCII, exporting to dBASE,
- reindexing, packing and so on.
- These member functions are very easy to use because they take very
- few, and often none, parameters. This is possible because a lot of the
- information which is specific for the database is already in the source of
- the functions.
-
- The generated class controls one database and all the indexes that
- come with it. If you need more then one database, as is to be
- expected, you have to repeat this procedure for the other databases as
- well.
-
- CSDBGEN does not aid in building the user-interface.
-
- An elaborate example is at the end of this chapter.
-
- 12.3 Features
-
- - Indexes with more then one reference to a record!
- This is an innovation! It makes it possible to locate a record by
- searching for a substring in the field, rather then the entire field.
- This topic is discussed in more detail in the paragraph 'tokenizing'.
- - Conversion to-and-from ASCII.
- This is convenient for backups, conversions to other systems and
- also for making changes in the record layout.
- - Export to dBASE compatible file format.
- CSDBGEN generates a function capable of writing out the contents
- of the database to a file which can be read by dBASE.
- - Can manage very large databases.
- The design of the libraries has been keen on avoiding limitations.
- By result, databases up to 2 billion records are theoretically
- feasible.
- - No overhead.
- Due to the use of a program generator, the overhead involved in
- accessing fields is next to none.
- - Large buffers.
- This system is capable of effectively using large amounts of RAM
- for buffering.
- - Fast.
- The precious two points, together with the efficient BTREEs
- guarantee a very fast database.
-
-
- 12.4 Limitations
-
- - No record locking.
- - No multi-user support.
- This system was designed to be used in single user applications.
- Time being, there is no support for network/shared databases.
- Perhaps there will be in the future but if so, it will take the form of
- a new series of classes.
-
-
- 12.5 Definition file
-
- The information needed to generate the new class is obtained from a
- 'definition file'. To get you started, the CSDBGEN utility is capable of
- generating an example.
-
-
- //example
-
- c:\borlandc>csdbgen /example>example.def
-
- Something like this will generate an example definition file 'example.def'.
-
-
-
- To get acquainted, let's look what's in it.
-
- Example definition file:
-
- class: NAM
- record: NAM_record
- file: demo
- field: name s 30 Y
- field: city s 20
- field: birthday d Y
- field: salary f
-
-
-
- Explanation:
-
- line 1: class: NAM
- The program generator generates a class, which of course has
- to have a name. In this example 'NAM' .
-
- line 2: record: NAM_record
- As explained before, the database system uses a C structure
- as a record. The name of this structure is defined in the
- second line.
- In the generated header file the following (among others) will
- appear:
-
-
- #define NAME_LENGTH 30
- #define CITY_LENGTH 20
-
- typedef struct
- {
- char _name[NAME_LENGTH+1];
- char _city[CITY_LENGTH+1];
- long __birthday;
- float _salary;
- } NAM_record;
-
-
- line 3: file: demo
- This line indicates the name of the files the database system
- is going to use. In this example three files will be used:
- - demo.dbf, the TBASE database file.
- - demo01.idx, the BTREE index file on field 'name'.
- - demo02.idx, the BTREE index file on field 'birthday'.
-
-
- line 4/7:
- Field definitions.
- The syntax for a field definition is:
- field: <field_name> <field_type> [length] [format] [index]
- With:
- field_name, the name of the field.
- field_type, the type of the field which can be:
- i: integer
- l: long
- f: float
- F: double
- c: character
- s: string
- length, only for strings.
- Indicates the number of characters the field needs to
- be able to store. One additional byte is reserved to
- store the null terminator.
- format, only for date fields.
- Please, see the documentation on DATE fields.
- To give a quick example: MDY4 means, Month, Day
- and 4 positions for the Year.
- index,
- 'Y' means a normal index.
- 'T' means a 'tokenized' index.
- Nothing means no index at all.
- See also the documentation on 'tokenizing' further on.
-
- In the example:
-
- field: name s 30 Y
- A field 'name' of type string. 31 Bytes are reserved, 30 for the
- characters and 1 for the null terminator. An index is
- maintained for this field because of the additional 'Y'.
-
- field: city s 20
- A field 'city' of type string with a length of 20 characters. There
- is NO index on this field.
-
- field: birthday d Y
- A field 'birthday' of type DATE. An index is placed on this field.
-
- field: salary f
- A field 'salary' of type float, without an index.
-
-
- 12.6 Tokenizing
-
- This is a new concept!
-
- Let's look at an example to make things clear.
-
- The demonstration database CSADDR, which comes with this package,
- uses tokenizing on its 'name' field.
-
- Let's say you have entered a record for the 'World Health Organization'.
- And now, for the first time in your life, can locate this record by entering
- 'health'. In fact, because CSADDR uses something called incremental
- search, entering just 'hea' is probably sufficient to pop up the record.
- It's important to know that this feature is not implemented by traversing
- the entire database from the first record to the last, as is done by some
- toy-applications.
-
-
- 12.6.1 How does it work?
-
- Traditionally, the index stores the entire field. In this example that would
- mean 'World Health Organization' is stored in the index together with a
- reference to the record number in the main database.
- With tokenizing, the index will store 3 entries, namely 'World', 'Health'
- and 'Organization'. This approach means that there will be a lot more
- entries in the btree then there are records in TBASE.
-
- In other words, an index is maintained on every suitable substring,
- rather then the entire field.
-
- To save disk space, the length of the key field in the BTREE
- is only half of the field length in the main database.
-
-
- 12.7 When is a substring indexed?
-
- First of all: tokenizing only applies for string fields. E.g. 'Tokenizing' a
- float field seams pointless.
-
- Whether or not a substring is put in the index is controlled by two
- things:
- - the way it is separated from the rest of the field.
- - the length of the substring.
-
- CSDBGEN generates a function 'tokenize'. This function contains a
- string 'delim' and a constant 'min_len'.
-
-
- // A part of the 'tokenize' function.
-
- char delim[]="\t,() "; // Token delimiters
- const min_len=4; // Minimum length for a token to be indexed
-
-
-
- The tokenize function separates the field into substrings according to
- the characters in the 'delim' array. Notice that the '.' is not a delimiter.
- This is to prevent abbreviations from being split up.
- A substring has to be at least four bytes long to appear in an index.
- This is not too long for most cases but it means that three letter
- abbreviations like 'IRS' are not indexed.
-
- Of course you can alter these two variables when needed.
-
-
- Example definition file:
-
- class: NAM
- record: NAM_record
- file: demo
- field: name s 30 T
- field: city s 20
- field: birthday d
- field: salary f
-
-
- Notice the 'T' behind the 'name' field. This is short for 'tokenize'. The
- generated class will maintain an index for the name field with
- references for every suitable substring.
-
- 12.8 Export to dBASE
-
- The program generator also produces a member function:
-
- int to_DBASE(char *filename);
-
- When called, this function produces a file 'filename' which can be read
- by dBASE. Index files are NOT written.
- At this moment there is no corresponding function to do the conversion
- the other way round.
-
-
- 12.9 Exporting/Importing to/from ASCII
-
- int export(char *filename);
-
- This writes out the contents of the database to an ASCII file 'filename'.
- That file will also contain information about the fields. In this way the
- import() function knows how to process this data, even after changes in
- the record layout.
-
- int import(char *filename);
-
- This member function reads the ASCII file 'filename' and appends its
- data to the current database. It is meant to be used in conjunction with
- the export() function. The export function starts of with writing the entire
- definition file. The import function uses this information to skip fields
- which are not in the database and to read fields in the right order. Only
- fields which are also in the current database are read, the others are
- ignored. This mechanism can be used to make changes in the record
- layout.
-
-
- 12.10 Starting a new database
-
- A member function
-
- void define(void);
-
- is available to create a new database. If the database already exists, it
- is overwritten!
-
-
- 12.11 Opening a database
-
- The member function
-
- void open(void);
-
- opens an existing database. To avoid errors, a blank record is inserted
- when an empty database is opened.
- Index files are automatically rebuilt if they don't exist.
-
-
- 12.12 Current Record
-
- At any moment there is always a record the 'current record'. The
- functions to read and write fields all work with this current record.
-
- - After opening, the first record becomes the current record.
- - The go_to(), skip(), top(), bottom() and the search() functions can be
- used to make another record 'current'.
-
-
- 12.13 Accessing fields
-
- CSDBGEN generates two member functions for each field. One to read
- the field, and a second to write the field. The names are the same but
- the arguments differ.
-
-
-
- Example:
-
- // A part of the definition file:
- class: NAM
- record: nam_record
- file: dbtest
- field: name s 40
- field: number i
-
- // We have a 'name' field consisting of a string with 40 characters
- // and a 'number' field which is an integer.
- // Among others, the next member functions are generated by CSDBGEN:
-
- class NAM
- {
- public:
- // For reading
- char *name(void);
- int number(void);
- // For writing
- void name(char *s);
- void number(int i);
- };
-
-
- The next example gives an impression of how the generated class
- could be used.
-
-
- Example:
-
- void main(void)
- {
- NAM db; // We now have a class 'NAM'.
-
- db.open(); // Open database. Assuming it already exists.
- // No file names have to be entered.
- // All the indexes are opened automatically.
-
- puts(db.name()); // Displays the name field of the first record.
- // After 'open' the first record is 'current'.
-
- db.name("Pjotr Idaho"); // Changes the contents of the 'name' field to
- // 'Pjotr Idaho'. Indexes are updated automatically.
-
- db.close(); // Close database.
- }
-
-
-
-
- 12.14 DATE fields
-
- Standard C doesn't support date variables. Therefore, this library has
- its own DATE class.
-
- The functions to read and write date-fields are using a string
- representation of a date. These strings can represent a date in several
- formats. CSDBGEN uses a default of DMY4. This means 2 positions for
- the Day, 2 positions for the Month and 4 positions for the Year.
-
-
- Example:
-
- "02/04/1994" // By default interpreted as: April the 2th 1994.
-
-
- When a two position representation of the year is wanted, use Y2
- instead of Y4.
- Every order of M,D,Y2 or Y4 is acceptable.
-
-
- Example:
- If you want "02/04/94" to be interpreted as February the 4th 1994, use the format
- MDY2. The line in the database definition file has to be:
-
- field: birthday d MDY2
-
- If you want the field to be indexed, add an additional 'Y':
-
- field: birthday d MDY2 Y
-
-
- For more information about the date formats, please see the
- documentation of the DATE class in the CSA-library.
-
- On disk, dates are stored as longs.
-
-
- 12.15 Changing the record layout.
-
- Even when the database is already in use, the need to make changes
- in the record layout may occur. With the next procedure this can be
- accomplished quite easily, without to the need to reenter any record
- manually.
-
- To put it in a nut shell: save your data to an ASCII file with the old
- export() function and reload with the new import() function.
-
- Or in more detail:
-
- a) Export with the 'old' export() function.
- This will produce an ASCII file which fully resembles the
- database.
- b) Make a new definition file or alter the old one.
- c) Generate a new Class with CSDBGEN.
- d) Compile & link.
- The last three steps are simply the procedure for creating a
- database using CSDBGEN.
- e) Use the new import() function to reload the data.
- Import the ASCII file created with step 'a'. The import()
- function is doing the actual conversion. It can do this because
- it has knowledge of both the old and the new definition file.
- The old one is on top of the ASCII file and knowledge about
- the new one is hard coded in the import() function by
- CSDBGEN.
-
-
- 12.16 Member functions in alphabetical order
-
- Next is a list of the public member functions as they appear in the
- generated class.
- With the sole exception of open() and define(), the database needs to
- be open for these functions to work properly.
-
- void append_blank(void);
- Appends an additional record to the database. The
- record is filled with binary zeros and becomes the
- current record.
- void bottom(void);
- The current record is set to the last record according
- to the active index.
- void close(void);
- Closes the open files. All buffers are flushed and all
- allocated memory is released. This function is called
- automatically by the class destructor if needed.
- long curr_rec(void);
- Returns the number of the current record. The first
- record is number 1.
- void define(void);
- Creates a new database. Files are generated for the
- database and all the indexes.
- If a file already exists, it's overwritten.
- void delet(void);
- Marks the current record for deletion. After the pack()
- function is called all the, in this way marked, records
- will be removed from the database.
- int export(char *filename);
- Writes the contents of the database to an ASCII file
- 'filename'. This file is meant to be read back by the
- import() function. The exported file contains a header
- which resembles the database 'definition file'. The
- function returns TRUE on succes, FALSE otherwise.
- void go_to(long rec_nr);
- The record 'rec_nr' becomes the current record. This
- is independent of the active index! The record is
- directly looked up in the main database, not through
- an index. Whether or not the record is marked for
- deletion makes no difference.
- int import(char *filename);
- Reads records from an ASCII file 'filename' generated
- by the export() function and appends these records to
- the database. TRUE is returned on success, FALSE
- otherwise.
- int is_delet(void);
- This function returns TRUE if the current record is
- marked for deletion, FALSE otherwise.
- long numrec(void);
- Returns the number of records currently in the
- database. The records marked for deletion are also
- counted.
- void open(void);
- Opens the database for use. The define() function
- has to be called, that is, the database file needs to
- exist. Index files are automatically generated if they
- are missing. A runtime error is produced if something
- fails.
- int order(void); Returns the number of the current active index.
- void order(int index_number);
- This function controls the use of indexes. The
- variable 'index_number' indicates which index has to
- become the active index. All the indexes however,
- are updated when a record is altered. In the header
- file a preprocessor constant is defined for each index.
- The name of this constant is generated by converting
- the field name to upper case and adding _INDEX.
-
- Example:
- An index on field: Street
- Preprocessor constant: STREET_INDEX
- <Class>.order(STREET_INDEX);
- will make the index on the street field the active index.
- <Class>.order(UNSORTED);
- makes all the indexes inactive.
-
- Changing the active index does not alter the current
- record. The preprocessor constant UNSORTED can
- be used to render all the indexes inactive. The
- database will be browsed in its 'natural' order.
- void pack(void);
- Removes all the records marked for deletion. No
- temporary files are used!
- void reindex(void);
- Rebuilds all the indexes of the database.
- void search(void *key);
- The active index is searched for value 'key'. The
- current record becomes the first record which
- matches the search value. The function accepts a
- pointer to the search argument. The reason is that
- the indexes are not (necessarily) of the same type.
- E.g. one index may search for integers while another
- searches for strings. In this way the same search
- function can be used, no matter the field type. When
- the search argument is not exactly matched, the
- current record becomes the record with a value 'close
- to' the required key. Normally this will be the next
- 'higher' value. This strategy proofs to work fine when
- searching for names etc..
- int skip(int delta);
- Makes another record the current record.
-
- Examples:
- skip(1); // The next record becomes the current record.
- skip(-1); // The previous record becomes the current record.
- skip(0); // Nothing happens.
- skip(10); // The record 10 positions to the end becomes
- // the current record.
-
- If an attempt is made to go 'before' the first record,
- record number 1 becomes the current record. Similar,
- the last record becomes the current record if an
- attempt is made to pass beyond the last record. The
- order in which the records are traversed is controlled
- by the current active index. The function returns the
- number of positions actually moved.
- int to_DBASE(char *filename);
- Exports the database to a file 'filename', which can
- be read by dBASE.
- Index files (for dBASE) are NOT generated.
- void top(void);
- The current record is set to the first record according
- to the active index.
- void undelet(void);
- If the current record is marked for deletion, this
- function removes the marker. Otherwise nothing
- happens.
-
-
- 12.17 Warning
-
- The program generator is not 'fool proof'. This means that you
- should avoid using names which already are reserved C++
- key words. E.g. if you try to define a field with the name
- 'delete' the resulting source will not compile.
-
- 12.18 Example
-
- Let's say we want to build a database with stores a person's name and
- his/hers birthday.
-
- Step 1
-
- First we need to construct a definition file. Next is a working example.
-
-
- class: BIRTH
- record: BRecord
- file: bdays
- field: name s 30 T
- field: birthday d Y4MD Y
-
-
- Assumes the name of this definition file is 'birth.def'.
-
-
- Step 2
-
- From the definition file we have to generate the source for the
- database. We do that by calling CSDBGEN.
-
-
- c:\borlandc\csutil\test> csdbgen birth.def
-
-
-
- This produces two output files: 'birth.cpp' and 'birth.h'.
- These names are derived from the name of the definition file. Not from
- the class name as one might expect from this example.
-
-
- Step 3
-
- We are now ready to start compiling. Normally, creating the database
- will be an option in the main menu of the application, but because this
- is a demonstration we do things differently.
-
-
- #include "birth.h"
-
- void main(void)
- {
-
- BIRTH db; // Declare an instance of the new BIRTH class.
-
- db.define(); // Create the database and its indexes.
-
- }
-
-
- Compile this together with the 'birth.cpp' file and link it.
-
- When ran, it should create three files:
- - 'bdays.dbf' The TBASE main database file.
- - 'bdays01.idx' The BTREEa index on the field name.
- - 'bdays02.idx' The BTREEl index on the field birthday. Remember,
- dates are stored as longs.
-
- If you run CSDIR in the same directory it will show something like this:
-
-
-
- Directory C:\BORLANDC\CSUTIL\TEST\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- BDAYS.DBF 174 TBASE 0 Nov 01 1994 Nov 01 1994
- BDAYS01.IDX 174 BTREEa 0 Nov 01 1994 Nov 01 1994
- BDAYS02.IDX 174 BTREEl 0 Nov 01 1994 Nov 01 1994
- --------------------------------------------------------------------------
- Total: 522 bytes in 3 files.
-
-
-
-
- Step 4
-
- By now, we have created the database files and we have the class to
- work with it. In other words, we are ready to write an 'application'.
-
-
-
- #include "iostream.h"
- #include "birth.h"
-
- void main(void)
- {
-
- BIRTH db; // Declare an instance of the new BIRTH class.
-
- db.open(); // Open it. Because it's empty, a blank record
- // is automatically added and becomes the current.
-
- db.name("Luke Skywalker"); // Modify the name.
- db.birthday("2015/07/03"); // Modify the birthday.
-
- db.append_blank(); // Add a new record. Becomes the current.
-
- db.name("Al Bundy"); // Modify the name.
- db.birthday("1945/11/30"); // Modify the birthday.
-
- db.reindex(); // Reindexing. For demonstration purposes.
- // Shouldn't be necessary.
-
- db.order(BIRTHDAY_INDEX); // Make BIRTHDAY the active index.
- db.top(); // Go to the oldest person.
- do
- { cout<<db.name()<<endl; } // Display his name.
- while(db.skip(1)); // Skip to the next.
-
- db.go_to(1); // Make record 1 the current record.
- // Index INdependent!
- db.delet(); // Mark it for deletion.
- db.pack(); // Remove it from the database.
-
- db.close(); // Close database and indexes.
- }
-
-
-
- If you run CSDIR again afterwards, you will see something like this:
-
-
-
- Directory C:\BORLANDC\CSUTIL\TEST\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- BDAYS.DBF 4096 TBASE 1 Nov 01 1994 Nov 01 1994
- BDAYS01.IDX 3072 BTREEa 1 Nov 01 1994 Nov 01 1994
- BDAYS02.IDX 3072 BTREEl 1 Nov 01 1994 Nov 01 1994
- --------------------------------------------------------------------------
- Total: 10240 bytes in 3 files.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Part
-
- Three
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Next are some classes which can be used where the traditional
- database will not do.
- A VRAM class is discussed which makes it possible to maintain
- pointer structures on disk.
- Two other classes, VBASE and VBAXE, are presented which deal
- with variable length records.
- In particular the beautiful VRAM class deserves attention!
-
-
- 13 VRAM
-
- 13.1 Introduction
-
- VRAM is without any doubt the most flexible and versatile class in this
- library. Contrary to the traditional database, this one doesn't suffer from
- fixed record sizes and doesn't have problems with deletions.
- In other words: it isn't a database at all!
-
- Assuming a C++ programmer has a good understanding of a 'heap', it
- shouldn't take long to explain this class. In one sentence, VRAM
- mimics a 'heap on a disk'.
-
- The idea is simple: use functions like 'malloc' and 'free' to manipulate
- the necessary space, just like with an ordinary heap, only this time the
- heap is in fact a file. In this way the data is not lost when the program
- exits while all the flexibility of a heap is still there!
-
- In a nut shell, that's what this class does. Apart from the indispensable
- functions 'define', 'open' and 'close', the class has mainly two functions:
- 'malloc()' and 'free()'.
-
-
- 13.2 Creating
-
- int define(char *name,U16 struclen);
-
- This is the function needed to create a VRAM system.
- Contrary to what you might have expected, it takes two parameters.
- The first is as usual the file name, the second however, is the
- maximum size you are planning to allocate.
-
- This differs from the ordinary heap which simply accepts allocations of
- any size right from the start. (Which also explains why the ordinary
- heap allocations are so amazingly inefficient.)
-
- In a way, the second parameter 'struclen' is a performance parameter.
- If you like, you could always use the maximum, which is 32 Kb, but this
- would yield a highly inefficient VRAM. The VRAM system will perform
- better the more accurate 'struclen' reflects the true state of affairs.
- However, performance option or not, 'struclen' is a very absolute upper
- limit to what you are allowed to allocate. Any attempt to allocate more
- will be answered with a runtime error.
-
-
- // Example VRAM define()
-
- #include "CSVRAM.H"
-
- void main(void)
- {
-
- VRAM vr;
- vr.define("VRAM.TST",614); // Allocating at most 614 bytes.
-
- }
-
-
-
- The CSDIR utility recognizes VRAM files. Afterwards it will display
- something like:
-
-
- Directory C:\BORLANDC\TEST\VRAM\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- VRAM.TST 174 VRAM 0 Nov 18 1994 Nov 18 1994
- --------------------------------------------------------------------------
- Total: 174 bytes in 1 files.
-
-
-
- 13.3 Opening & Closing
-
- Like all the databases classes in this library, VRAM needs to be
- 'opened' before it can be used and, consequently, 'closed' afterwards.
-
- syntax: int open(char *name,U16 kb_buf);
-
- This opens the vram file 'name' and uses 'kb_buf' Kb for buffering.
-
- syntax: int close(void);
-
- This closes the VRAM system. This function is also called by the class
- destructor when needed.
-
-
- // Example VRAM
-
- #include "CSVRAM.H"
-
- void main(void)
- {
-
- VRAM vr;
- vr.define("VRAM.TST",614); // Allocating at most 614 bytes.
-
- vr.open("VRAM.TST",300); // Opens VRAM.TST using 300 Kb buffers.
-
- // Doing something interesting.
-
- vr.close(); // Close VRAM system.
- }
-
-
-
-
- 13.4 VRAM Pointers
-
- The normal malloc() function returns a void pointer, unfortunate VRAM
- cannot do that. It uses its own type of pointer: VPOI which is short for
- Virtual POInter. VPOI is a simple 32 bit unsigned long, defined in
- 'CSVRAM.H'. VPOI also limits the size of a VRAM system. With 32 bits
- 4 Gb can be addressed, no more. Of course you can always use more
- then one VRAM system in your application when pressed for space!
-
- There is another important difference between VRAM and a normal
- heap. VRAM distinguishes between reading and writing. The buffer
- system used, cannot tell whether you are making changes. Therefore,
- the programmer need to supply that information by calling different
- functions for reading and writing.
-
- Reading: char *R(VPOI p);
- Writing: char *W(VPOI p);
-
-
- // Example
-
- #include "CSVRAM.H"
-
- void main(void)
- {
-
- VRAM vr; // A VRAM system.
- VPOI vp; // A VRAM pointer.
- char *cp; // A normal character pointer.
-
- vr.define("VRAM.TST",614); // Initially create it.
-
- vr.open("VRAM.TST",50); // Opening with 50 kB buffers.
-
- vp=vr.malloc(20); // Allocate 20 bytes from the virtual heap.
-
- cp=vr.W(vp); // Obtaining a character pointer to
- // the allocated space. We are planning to
- // write, so the 'W' function is used.
-
- strcpy(cp,"Some Data"); // Write data into it.
-
- vr.close(); // Close the VRAM system.
- // "Some Data" is now on disk!
-
- }
-
-
-
- From the above example it becomes clear how the VPOI pointers can
- be used. The method is simple: convert them into normal pointers and
- apply standard C++ programming technique.
-
- Only the last 2 converted VPOI pointers are guaranteed to be
- valid. VRAM has a limited number of buffers, so you cannot
- expect all data to be in ram forever.
- Every time you convert a VPOI pointer into a character pointer by using
- the W() or the R() function, VRAM calculates the corresponding position
- in the file and loads the required page in ram. The pointer returned
- points directly into this page. Because only the last two pages are
- guaranteed to be in ram under all circumstances, the third time you
- convert a VPOI pointer, it can overwrite a previously loaded page.
-
- Because at least two pointers are valid, you can copy data from one
- VRAM position to another without using temporary storage.
-
- With the W() function, the loaded page is marked 'dirty' which makes
- sure it's written back to disk when the page is removed from the buffer
- system. This is not so for the R() function. In that case the page is
- simply discarded.
-
-
- // Example, copying between two VPOI pointers.
-
- #include "CSVRAM.H"
- void main(void)
- {
-
- VRAM vr;
- VPOI vp1,vp2;
-
- vr.open("VRAM.TST",50); // Opening with 50 kB buffers.
-
- strcpy(vr.W(vp1=vr.malloc(20)),"Some Data"); // Allocate and fill
- // one VPOI.
-
- vp2=vr.malloc(100); // Allocate a second.
-
- memcpy(vr.W(vp2),vr.R(vp1),20); // Copy!
-
- vr.close(); // Close the VRAM system.
- }
-
-
-
- 13.5 Fragmentation
-
- Just as with an ordinary heap, VRAM can suffer from fragmentation.
- The normal heap can become prematurely exhausted because of
- fragmentation while for the VRAM system it only means the file
- becomes larger then strictly necessary.
- On the other hand: the normal heap gets a fresh start every time the
- program is run while the VRAM files may be in use for years.
-
- Therefore a defrag() function is available. If you decide to use it, it is
- best to use it regularly. It mainly does three things:
- a) Joining free space wherever possible.
- This is not done during normal operation because it may involve
- additional IO.
- b) Sorting the empty-data-chains.
- When space is needed, its taken from the beginning of a empty-
- chain. After sorting the chains, the empty blocks at the beginning
- of the file will also be at the beginning of the chain. Eventually this
- leads to pages at the end becoming completely free and pages at
- the beginning (almost) full.
- c) Empty pages above the highest used location are stripped from the
- file.
-
- The defrag() function links in a lot of code, it uses an entire
- btree and a temporary file. In a way this makes the defrag()
- function 'bigger' then the rest of the VRAM class combined!
-
- 13.6 Root
-
- Under some circumstances you may need a 'starting point' in the
- VRAM.
- Example:
- Let's say you are writing some flowcharting program and you have
- decided that VRAM is a great help in storing and manipulating a
- flowchart. The flowchart probably consists of several independent
- parts pointered together. Once in it, each part can be reached by
- the VPOI's stored in the data structure. This leaves you with just
- one problem: where does the flowchart start?
- It takes just one VPOI to store that location and it would be a
- shame if you needed an additional configuration file for that.
-
- Therefore two very simple functions are implemented to store and
- retrieve a 'special' VPOI.
-
- void root(VPOI p); Stores VPOI 'p'.
- VPOI root(void); Obtains the VPOI stored with the previous
- function.
-
- These functions just manipulate this single VPOI. They have absolutely
- no effect on the rest of the VRAM system.
-
- 13.7 Functions in Alphabetical order.
-
- Prototypes are in 'csvram.h'. With the exception of the define(). open()
- and zap() functions, the class needs to be opened for the functions to
- work.
-
- U16 alloc(VPOI p);
- U16 alloc(void *p);
- Returns the number of allocated bytes at a certain
- location. The pointer may be either a VPOI pointer or
- a normal pointer to the same location.
- int close(void); Closes the VRAM system. Returns TRUE on
- success, FALSE otherwise.
- int define(char *name,U16 struclen);
- Creates the VRAM system 'name' with 'struclen'
- being the maximum size of any allocation. Returns
- TRUE on success, FALSE otherwise.
- int defrag(void); Defragments the virtual heap. Returns TRUE on
- success, FALSE otherwise.
- int empty(void); Makes the VRAM system empty. The class remains
- open but all allocations will be undone. Returns
- TRUE on success, FALSE otherwise.
- U32 number(void);
- Returns the number of allocations currently done.
- This is the number of malloc()'s minus the number of
- free()'s.
- int open(char *name,S16 kb_buf);
- Opens VRAM 'name' using 'kb_buf' Kb ram for
- buffering. Returns TRUE on success, FALSE
- otherwise.
- char *R(VPOI p);
- Converts a VPOI pointer into a character pointer. It is
- assumed no modifications are going to take place.
- void root(VPOI p);
- Stores VPOI 'p'.
- VPOI root(void); Obtains the VPOI stored with the previous functions.
- int save(void); Makes a safety backup. The VRAM system remains
- open. All the buffers are flushed and the header page
- is updated. Returns TRUE on success, FALSE
- otherwise.
- void free(VPOI p);
- Frees the VPOI p.
- VPOI malloc(U16 size);
- Allocates 'size' amount of bytes from the virtual heap.
- The corresponding VPOI is returned.
- char *W(VPOI p);
- Converts a VPOI pointer into a character pointer. It is
- assumed modifications are going to take place.
- int zap(void); Closes the VRAM system when needed and restores
- all class defaults. Returns TRUE on success, FALSE
- otherwise.
-
- 14 VBASE
-
-
- 14.1 Introduction
-
- The use and purpose of the VBASE class are much similar to the
- TBASE class. There is however, one huge difference, VBASE supports
- variable length records! The 'V' in VBASE stands for 'variable'.
-
- Compared with TBASE, the differences in the public member functions
- are minimal. The append() function now takes an additional parameter
- indicating the length of the record. The same goes for the write_rec()
- function. Apart from the 'normal' read_rec() function there is now an
- additional read_rec() which returns the length of the obtained record.
-
- VBASE is a 'stand alone' class. It has nothing to do with the
- databases produced by CSDBGEN.
-
-
-
- 14.2 Using VBASE.
-
- Using VBASE is very straightforward.
-
- - Initially create the VBASE system by calling define().
- - Open it through a call to open().
- - Read, write and append records.
- - Close VBASE by calling close().
-
- That's all!
-
-
- // Example
-
- #include "csvbase.h"
-
- void main(void)
- {
-
- VBASE vb;
-
- vb.relocate_when_shrunk(TRUE); // Move the record to a better
- // fitting position when shrunk.
- vb.define("VBASE.dbf",1230); // Maximum record length 1230 bytes.
-
- vb.open("VBASE.dbf", 200); // Open with 200 Kb buffers.
-
- char *s="Some chunk of data. ";
-
- vb.append_rec(s,strlen(s)+1); // Append a record. Notice the length
- // parameter which is not needed with
- // TBASE.
- char d[200];
- vb.read_rec(1,d); // Read record 1 into array 'd'.
-
- strcpy(d,"New Data");
-
- vb.write_rec(1,d,strlen(d)+1); // Overwrite record 1 with a new
- // block of data. This does not have
- // to have the same length!
-
- vb.close(); // Ready. Close VBASE. Also called by
- // the class destructor if needed.
-
- }
-
-
- For more information, please read the documentation on the TBASE
- class.
-
-
- 14.3 Relocating records
-
- When an existing record is overwritten with a new bigger record, it no
- longer fits in its original slot, which means the record has to be
- relocated. This is not necessarily so when the record shrinks. In that
- case you have the choice between relocating, which saves disk space
- but is relatively slow or leaving the record where it is and waste some
- disk space.
-
- The function 'relocate_when_shrunk()' is there to choose between these
- two strategies. It has to be called before 'define()'.
- Calling 'relocate_when_shrunk(TRUE);' will relocate a record when it
- becomes smaller. 'Relocate_when_shrunk(FALSE);' will leave the
- records in place when possible.
- The default is set to: relocate_when_shrunk(TRUE).
-
- The function has to be called before 'define()' and its setting
- cannot be altered afterwards.
-
-
-
- 14.4 Limitations.
-
- VBASE was designed for databases up to around a million records.
- This is not a 'hard' limit, its possible to add many more records but
- under some unfavourable conditions memory utilization can get out of
- control. The way the class uses the available ram is controlled by the
- open() function. The worst thing you can do is open an empty VBASE
- and append 3 million records in one go. In this way the class cannot
- adjust the way its using memory. If the records are not appended all at
- once but with several close/open sequences in between, VBASE can
- easily store 16 million records.
-
- So:
- - Under worst case conditions 1 million records.
- - Under favourable conditions 16 million records.
- - Avoid more then 16 million records.
-
- The above limitations stem from ram utilization. For those drowning in
- memory, there are also software limitations:
- - maximum file size 4 Gb.
- - 4 billion records.
-
-
- Because there are so many 'buts' and 'ifs', there is another class
- VBAXE, discussed in the next chapter, to deal with the larger
- databases.
-
- As a rule of thumb, use VBASE for databases up to 1 million
- records and VBAXE for more then 1 million records.
-
- 14.5 Functions in alphabetical order.
-
- The function prototypes are in csvbase.h.
-
-
- U32 append_rec(void *data,U16 len);
- Append a record to the database. 'data' is a pointer
- to the data and 'len' is the number of bytes data. The
- function returns the number of the newly created
- record.
- int close(void);
- Closes the database. All buffers are flushed and all
- allocated memory is freed. TRUE is returned on
- success, FALSE otherwise.
- int define(char *name,U16 struclen);
- Creates a new database. 'name' is the name of the
- file and 'struclen' is the maximum length of a record.
- Do not make 'struclen' unnecessary large because its
- value is important for space efficiency. The maximum
- value of struclen is 32767. TRUE is returned on
- success, FALSE otherwise.
- void delet(U32 record);
- Marks record 'record' for deletion. Only the 'delete bit'
- is set. The pack() function needs to be called to
- actually remove the record from the file.
- void empty(void);
- Removes all records from the database. Upon return
- the database will contain zero records but will still be
- 'open'.
- int is_delet(U32 record);
- Returns TRUE if record 'record' is marked for
- deletion. FALSE otherwise.
- U32 numvrec(void);
- Returns the number of records currently in the
- database.
- int open(char *name,U16 kb_buf);
- Opens database 'name', using 'kb_buf' Kb ram for
- buffering. Returns TRUE on success, FALSE
- otherwise.
- int pack(void); Removes all records marked for deletion. A
- temporary file is used. TRUE is returned on success,
- FALSE otherwise.
- void read_rec(U32 rec,void *ptr,U16 &length);
- Reads record 'rec' and copies it into the buffer 'ptr' is
- pointing at. The variable 'length' is set to the length of
- the retrieved record.
- void read_rec(U32 pos,U16 maxlen,void *ptr,U16 &length);
- The same as the precious function but with an
- additional parameter 'maxlen' specifying the
- maximum number of bytes that can be copied into
- the buffer 'ptr'. If the record proofs to be longer then
- 'maxlen', only 'maxlen' bytes will be copied to 'ptr'.
- U16 rec_len(U32 rec);
- Returns the length of record 'rec'.
- void relocate_when_shrunk(int TrueOrFalse);
- When called with 'TrueOrFalse' set to TRUE, records
- will be relocated when shrunk. When called with
- FALSE the records will stay at the same place. The
- function has to be called before define(). For more
- information, please see the paragraph about this
- topic.
- int save(void); As a precaution measure, all 'dirty' buffers are written
- to disk and the header page is updated. The
- database remains open. Returns TRUE on success
- and FALSE otherwise.
- void undelet(U32 rec);
- Removes the 'delete' marking from record 'rec'.
- void write_rec(U32 rec,void *data,U16 len);
- Overwrites the existing record 'rec'. 'len' bytes are
- copied from 'data'. Afterwards the record will be of
- length 'len'.
-
- 15 VBAXE
-
- 15.1 Introduction
-
- As explained in the previous chapter, VBAXE is similar to VBASE but is
- intended for larger databases. That is, more then 1 million records.
-
- The public member functions of the classes are 100% identical. The
- inner workings however are completely different. VBAXE uses two files
- for a database where as VBASE uses only one. VBAXE is build from
- two other classes namely TBASE and VRAM.
-
- Building a class for variable length records is not easy, but writing one
- that can store millions of records, is fast, uses little ram, doesn't use
- unnecessary disk space and still stores everything in one file is next to
- impossible.
- So, rather then coming up with something slow & clumsy, VBAXE gives
- up on storing everything in one file which seems to be the lesser evil.
-
-
- 15.2 Working.
-
- The working of VBAXE is very simple. It allocates the necessary space
- from VRAM and stores the VRAM pointer together with the length in a
- TBASE record.
- E.g. to obtain record 714 it starts with retrieving record 714 from
- TBASE. Because TBASE uses fixed size records, the position of record
- 714 can easily be calculated. Once this record is obtained, the VRAM
- pointer to the data of record 714 is known. From this pointer the
- position in the VRAM file can again be easily calculated. If nothing is in
- the buffers, it takes two IO's to obtain the data, but at least no
- searching is done. The positions in the files are always known through
- simple arithmetic. (This also holds for the VBASE class.)
-
-
- 15.3 Files
-
- As explained above there are two files to every VBAXE database. The
- TBASE part stores it's data in a file with extension '.vbi'. The VRAM
- part uses extension '.vbd'. No matter what names are used in the
- define() or the open() functions, these are the extensions used.
- The CSDIR utility recognizes these files and will display the TBASE
- class as VBASEi and VRAM as VBASEd. In this way its immediately
- apparent they belong to the same database.
-
-
- // Example
-
- #include "csvbaxe.h"
-
- void main(void)
- {
- char buf[1000];
-
- VBAXE vb;
- vb.define("demo",390); // Max record length 390 bytes.
-
- vb.open("demo",200); // 200 Kb buffers.
-
- for(int i=1;i<=100;i++)
- {
- vb.append_rec(buf,1+random(390)); // Append 100 records
- // with random length
- // and random contents.
- }
-
- vb.close(); // Close database.
- }
-
-
- Afterwards CSDIR will display something like:
-
-
-
- Directory C:\BORLANDC\DEMO
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- DEMO.VBI 4096 VBASEi 100 Dec 14 1994 Dec 14 1994
- DEMO.VBD 26624 VBASEd 100 Dec 14 1994 Dec 14 1994
- --------------------------------------------------------------------------
- Total: 30720 bytes in 2 files.
-
-
-
- However, CSINFO still says DEMO.vbi is a TBASE file and DEMO.vbd
- a VRAM file.
-
-
- 15.4 Prototypes.
-
- The class defintion and it's function prototypes are in "CSVBAXE.H".
-
-
-
-
-
-
-
-
- Part
-
- Four
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Part Four will present some command-line utilities.
- Most noticeable CSDIR, which gives a quick survey of the
- databases in the current directory.
- It also discusses the demonstration application CSADD.
- CSADD is a DOS application to store addresses. 16 CSDIR
-
-
- CSDIR is an on-line utility similar to the well-known MS-DOS dir.
- It's purpose is to list the CS-databases. By default it ignores all other
- files.
-
- SYNTAX: csdir [filename] [/A] [/?]
-
- filename: the file(s) to be listed. Wildcards allowed.
- /A List all files.
- /? Display help.
-
- Example of its output:
-
-
- c:\bin\adres>csdir
-
-
- Directory C:\BIN\ADRES\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- CSADR.DBF 98382 TBASE 298 Sep 20 1994 Oct 31 1994
- CSADR01.IDX 40960 BTREEa 403 Oct 29 1994 Oct 31 1994
- CSADR02.IDX 10752 BTREEa 104 Oct 29 1994 Oct 31 1994
- CSADR03.IDX 4608 BTREEl 28 Oct 29 1994 Oct 31 1994
- CSADR04.IDX 5120 BTREEa 22 Oct 29 1994 Oct 31 1994
- --------------------------------------------------------------------------
- Total: 159822 bytes in 5 files.
-
-
-
- As can be seen from this example, CSDIR displays:
- - the name of the class involved.
- - the number of entries in the database.
- - in case of a btree, the number of different keys. If the same key
- is entered twice, it is counted as one entry.
- - date of creation.
- - date of last update.
-
- Example of the /a option.
-
-
- c:\bin\adres>csdir /a
-
-
- Directory C:\BIN\ADRES\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- ADRES.EXE 137872 DOS Oct 29 1994
- CSDEMIO.DEF 277 DOS Apr 17 1994
- BACKUP.TXT 34478 DOS Oct 29 1994
- CSADR.DBF 98382 TBASE 298 Sep 20 1994 Oct 31 1994
- CSADR01.IDX 40960 BTREEa 403 Oct 29 1994 Oct 31 1994
- CSADR02.IDX 10752 BTREEa 104 Oct 29 1994 Oct 31 1994
- CSADR03.IDX 4608 BTREEl 28 Oct 29 1994 Oct 31 1994
- CSADR04.IDX 5120 BTREEa 22 Oct 29 1994 Oct 31 1994
- ERROR.ERR 12964 DOS Oct 27 1994
- --------------------------------------------------------------------------
- Database files: 159822 bytes in 5 files.
- Other files: 185591 bytes in 4 files.
- -------- + --- +
- Total: 345413 bytes in 9 files.
-
-
-
-
- Another example:
-
-
- c:\bin\adres>csdir cs*.* /a
-
-
- Directory C:\BIN\ADRES\
-
- Name Size Type Entries Created Updated
- --------------------------------------------------------------------------
- CSDEMIO.DEF 277 DOS Apr 17 1994
- CSADR.DBF 98382 TBASE 298 Sep 20 1994 Oct 31 1994
- CSADR01.IDX 40960 BTREEa 403 Oct 29 1994 Oct 31 1994
- CSADR02.IDX 10752 BTREEa 104 Oct 29 1994 Oct 31 1994
- CSADR03.IDX 4608 BTREEl 28 Oct 29 1994 Oct 31 1994
- CSADR04.IDX 5120 BTREEa 22 Oct 29 1994 Oct 31 1994
- --------------------------------------------------------------------------
- Database files: 159822 bytes in 5 files.
- Other files: 277 bytes in 1 files.
- -------- + --- +
- Total: 160099 bytes in 6 files.
-
-
-
-
-
- 17 CSINFO
-
-
- CSINFO is an on-line DOS utility to display information about a
- particular database.
- It only recognizes the databases made with the CSDB-library.
-
- An example of its output:
-
-
-
- c:\adres>csinfo csadr01.idx
-
-
- Information about database: csadr01.idx.
-
- Type..................: BTREEa
- Version...............: 1.0.a
- Class compiled at.....: Sep 05 1994, 04:28:24
- With..................: Borland C++ 3.1
-
- NOTE: The above information refers to the version of the
- class used during the CREATION of the database file.
-
- Btree created at......: September 20 1994, 10:02:11,47
- Btree last updated at.: September 26 1994, 23:25:19,96
- Multiple keys allowed.: YES
- Number of keys........: 622
- Number of blocks......: 111
- Block size............: 511 bytes
- Key size..............: 41 bytes
- Data size.............: 4 bytes
- Data degree...........: 10
- Index degree..........: 10
- Number of levels......: 4
-
-
-
- 18 CSERROR
-
-
- Normally all the errors are read from a file. This is the file 'error.err'.
- It has to be in the current working directory or it cannot be found.
-
- The advantage in using a runtime error file is of course the smaller
- executable that results from leaving out all the possible error
- messages.
- The error file is not kept open all the time. For opening a file, some
- dynamic memory allocations have to be done. This can lead to
- problems when the error message that has to be displayed results from
- an 'out of memory' condition.
- (It needs memory to say 'there is no more memory'.)
-
- To overcome this and other problems, CSERROR can be used.
- It generates C source that makes the runtime error file redundant.
-
-
- Example:
- c:\borlandc>cserror error.err
-
-
- This will produce a file 'error.cpp' in the current directory. Compile this
- and link it in with the rest of your application, but before the libraries. In
- this way the 'error.obj' will replace the 'csmess_read()' function which is
- in the library.
-
-
- // Example of how the resulting 'error.cpp' file could look:
- // Many errors are left out.
-
-
- #include "csmess.h"
-
- char *_csa_error[]=
- {
- "Error 9370: TBASE: %s Can't write report file %s. Disk full?",
- "Error 9390: TBASE: %s Out of memory during pack().",
- "Fatal Error 9545: PAGE: %s Header_2_data(): can't perform fseek.",
- "Fatal Error 9550: PAGE: %s Write_header: can't perform fwrite.",
- "Fatal Error 9555: PAGE: %s Header_2_data(): can't perform fread.",
- "Fatal Error 9560: PAGE: %s Can't open file during definition.",
- "Error 9562: PAGE: %s Can't open report file %s.",
- "TheEnd" //THIS HAS TO BE THE LAST LINE!!
- };
-
- /////////////////////////////////////////////////////////////////////
-
- char *csmess_read(long error)
- {
- char tmp[25];
- ltoa(error,tmp,10);
- char **p=_csa_error;
- for(;;)
- {
- if(strstr(*p,tmp)) return *p;
- if(!strcmp(*p,"TheEnd")) return NULL;
- p++;
- }
-
-
-
- Notice the 'TheEnd' line, which was not in the original
- 'error.err' file. Never remove that line!
-
-
-
-
-
-
-
-
-
-
-
- 19 CSADD
-
-
- 19.1 Source
-
- This is a demonstration database for storing addresses.
- It gives an adequate impression of what this library was designed for.
- No complex client/server approach but strait forward functions to read
- and write records.
- The user interface is written with the aid of the CSA-library.
-
- The source consists of two files: 'csadd.cpp' for the user-interface and
- 'csaddio.cpp' for the database.
- - 'csaddio.cpp' is generated by the CSDBGEN utility with the file
- 'csaddio.def' as input.
- - 'csadd.cpp' is 'hand coded'. The file is about 500 lines.
-
-
- 19.2 Openings screen
-
- This is how it is supposed to look:
-
-
- eXit Insert Delete Edit Sort order Output Utilities Setup Help=F1
- ┌──────────────────────────────────────────────────────────────────────────────┐
- │ ╔══════════════════════ Address DataBase ═══════════════════════╗ │
- │ ║ Updated: 09/29/94 ║ │
- │ ║ ║ │
- │ ║ Name: City: ║ │
- │ ║ Roberta Grundburg Kopenhagen ║ │
- │ ║ ║ │
- │ ║ Address: Telephone: ║ │
- │ ║ 23 Grondlsy 0978-234-56756 ║ │
- │ ║ ║ │
- │ ║ Zip code: Country: ║ │
- │ ║ TY 2347 Denmark ║ │
- │ ║ ║ │
- │ ║ Birthday: Relation: ║ │
- │ ║ 12/04/1977 45 ║ │
- │ ║ ║ │
- │ ║ Info: ║ │
- │ ║ ║ │
- │ ╚═══════════════════════════════════════════════════════════════╝ │
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
- │ │ Command: rob Record 243/243 │ │
- │ └───────────────────────────────────────────────────────────────────────┘ │
- └──────────────────────────────────────────────────────────────────────────────┘
-
-
-
- 19.3 Features
-
- This simple demonstration database has already some interesting
- features:
- - Incremental search. That is, it 'zero's in' on the name you are
- looking for with every key entered. Normally it finds the
- required record after only two or three characters.
- - Exporting to a dBASE compatible file. The files used by the
- application are not in the dBASE format, but they can be
- exported to a dBASE compatible file.
- - Indexing also on substrings. Contrary to the traditional database,
- this one is capable of locating a record by searching for a
- substring of the key field, rather then the entire field.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Part
-
- Five
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Part Five discusses the classes and functions implemented in the
- CSA-library.
- They have nothing to do with databases so you can use or ignore
- them at will.
- However, two chapters may require some attention.
- Alloc-logging which deals with heap corruption and memory leaks.
- The HEAP class for efficiently allocating large numbers of small
- blocks.
-
-
-
- 20 CSTOOLS
-
- 20.1 Introduction
-
- A collection of odds & ends, merely intended to support the other
- classes, but if you see something to your liking, please feel free to use
- it.
-
- The function prototypes are in cstools.h.
-
- int add_path(char *filen,char *path);
- Adds path 'path' to filename 'filen'. Afterwards 'filen'
- contains the new name. It returns TRUE if successful,
- FALSE otherwise.
- void box(int row,int col,int h,int w,int border,int color);
- Draws a box on the screen. (Non graphical.)
- row: top row
- col: left column
- h: height
- w: width
- border: type of border
- BORDER_NONE, BORDER_SPACE
- BORDER_SINGLE, BORDER_DOUBLE
- color: text ATTRIBUTE of the border line.
- int csrand(long int);
- long csrand(long amount);
- Returns a VERY random number in the range
- 0..(amount-1), including both 0 and (amount-1).
- int cstmpname(char *name);
- Generates the name of a non-existing file in the
- 'temp' directory. It first searches for the environment
- variable 'TMP' and if not found for 'TEMP'. A filename
- is generated which does not already exist in this
- directory. The function has to be called with a
- parameter 'name' pointing to a buffer large enough to
- hold the complete drive, path and filename. If non of
- the evironment variables exist, a filename for the
- current directory is produced. It only generates a
- filename, no file is actually created. The function
- returns TRUE if a unique filename was found, FALSE
- otherwise.
- int disk(char *s);
- Sets the current drive and path as indicated by string
- 's'. If 's' is the empty string, 's' is set to the current
- drive and path! It returns TRUE if successful, FALSE
- otherwise.
- void empty_kb(void);
- Empties the keyboard buffer.
- int file_exist(char *fnaam);
- Returns TRUE if file 'fnaam' exists.
- char *file_ext(char *name,char *ext);
- Adds an extension to filename 'name'. It returns a
- pointer to an internal buffer which contains the new
- name. If 'name' already has an extension, it is
- overwritten. The string 'name' itself is not changed!
- long filesize(char *name);
- Returns the size of file 'name'.
- void filter_string(char *source,char *allowed);
- All the characters in 'source' which are not in
- 'allowed' are removed from 'source'.
- void gotoyx(int y,int x);
- Same as Borlands gotoxy(x,y) but with reversed
- parameters.
- int is_color(void);
- Returns TRUE if you are using a color screen.
- FALSE otherwise.
- void lower_upper(char *ptr);
- Converts the entire string to upper case.
- long lrandom(long amount);
- Returns a long random number in the range
- 0..(amount-1), including both 0 and (amount-1).
- int make_color(int fgc,int bgc);
- Returns the text attribute corresponding with the Fore
- Ground Color (fgc) and the Back Ground Color (bgc).
- size_t next_prime(size_t pri);
- Calculates next higher prime number.
- char *notabs(char *s);
- Replaces every occurrence of a tab character in 's'
- with a single space. That is: tabs are not expanded,
- but simply removed.
- char *remove_space(char *s);
- Removes ALL the blanks from the string 's'. It returns
- character pointer 's'.
- unsigned int sqrti(unsigned int n);
- unsigned long sqrtl(unsigned long n);
- Calculates the sqrt from n WITHOUT USING
- FLOATING POINT arithmetic.
- void str_split(char *source,char ch,char *first,char *last);
- Split 'string' source at the first occurrence of character
- 'ch'. Ch is included in neither the 'first' nor the 'last'
- string.
- void str_strip(char *source,char *remove);
- Characters in 'source' which are also in 'remove' are
- removed from 'source'.
- int str_equal(char *s1, char *s2);
- Returns TRUE if 's1' is equal to 's2', discriminating
- between upper and lower case.
- void str_left(char *source,char *dest,int len);
- Copies at most 'len' number of characters from the
- left of 'source' to 'dest'.
- char *string_replace_ones(char *source,char *d,char *r);
- Replaces the first occurrence of 'd' in 'source' with 'r'.
- int string_replace(char *s,char *d,char *r);
- Replaces every occurrence of 'd' in 'source' with 'r'. It
- returns an integer number indicating the number of
- times a substitution was made.
- long time_stamp(void);
- Returns a higher long number on each successive
- call, starting with zero again when MAXLONG is
- reached.
- void trim_string(char *s);
- Removes heading and trailing blanks from string 's'.
- void wait(long msec);
- Waits 'msec' milliseconds.
- void waitkb(long msec);
- Waits 'msec' milliseconds or until the next keyboard
- hit.
-
- 21 CSKEYS
-
-
- Almost all the input for the library functions is done through the cskey()
- function.
-
- Syntax:
- int cskey(void);
-
- The return value can be one of the following: ( defined in CSKEYS.H )
-
-
- CTRL_A KEY_A KEY_a ALT_A DELETE CURSOR_UP
- CTRL_B KEY_B KEY_b ALT_B END CURSOR_DOWN
- CTRL_C KEY_C KEY_c ALT_C HOME CURSOR_RIGHT
- CTRL_D KEY_D KEY_d ALT_D PAGE_UP CURSOR_LEFT
- CTRL_E KEY_E KEY_e ALT_E PAGE_DOWN
- CTRL_F KEY_F KEY_f ALT_F INSERT
- CTRL_G KEY_G KEY_g ALT_G BACKSPACE
- CTRL_H KEY_H KEY_h ALT_H TAB
- CTRL_I KEY_I KEY_i ALT_I SHIFT_TAB
- CTRL_J KEY_J KEY_j ALT_J ENTER
- CTRL_K KEY_K KEY_k ALT_K ESC
- CTRL_L KEY_L KEY_l ALT_L SPACE
- CTRL_M KEY_M KEY_m ALT_M
- CTRL_N KEY_N KEY_n ALT_N CTRL_DELETE
- CTRL_O KEY_O KEY_o ALT_O CTRL_HOME
- CTRL_P KEY_P KEY_p ALT_P CTRL_CURSOR_UP
- CTRL_Q KEY_Q KEY_q ALT_Q CTRL_CURSOR_DOWN
- CTRL_R KEY_R KEY_r ALT_R CTRL_CURSOR_RIGHT
- CTRL_S KEY_S KEY_s ALT_S CTRL_CURSOR_LEFT
- CTRL_T KEY_T KEY_t ALT_T CTRL_PAGE_UP
- CTRL_U KEY_U KEY_u ALT_U CTRL_PAGE_DOWN
- CTRL_V KEY_V KEY_v ALT_V CTRL_END
- CTRL_W KEY_W KEY_w ALT_W
- CTRL_X KEY_X KEY_x ALT_X
- CTRL_Y KEY_Y KEY_y ALT_Y
- CTRL_Z KEY_Z KEY_z ALT_Z
-
- F1 SHIFT_F1 CTRL_F1 ALT_F1 KEY_1 ALT_DELETE
- F2 SHIFT_F2 CTRL_F2 ALT_F2 KEY_2 ALT_HOME
- F3 SHIFT_F3 CTRL_F3 ALT_F3 KEY_3 ALT_CURSOR_UP
- F4 SHIFT_F4 CTRL_F4 ALT_F4 KEY_4 ALT_CURSOR_DOWN
- F5 SHIFT_F5 CTRL_F5 ALT_F5 KEY_5 ALT_CURSOR_RIGHT
- F6 SHIFT_F6 CTRL_F6 ALT_F6 KEY_6 ALT_CURSOR_LEFT
- F7 SHIFT_F7 CTRL_F7 ALT_F7 KEY_7 ALT_PAGE_UP
- F8 SHIFT_F8 CTRL_F8 ALT_F8 KEY_8 ALT_PAGE_DOWN
- F9 SHIFT_F9 CTRL_F9 ALT_F9 KEY_9 ALT_END
- F10 SHIFT_F10 CTRL_F10 ALT_F10 KEY_0
- F11 SHIFT_F11 CTRL_F11 ALT_F11
- F12 SHIFT_F12 CTRL_F12 ALT_F12
-
- The predefined values for the 'normal' keys like 'A', 'a' or '1'
- are the same as the ASCII values. This means you are not
- forced the type things like
-
- if( KEY_A==cskey() ) ....
-
- but can also use:
-
- if( 'A'==cskey() ) ......
-
-
- 21.1 CSKEYS.exe
-
- There is also a simple utility to test the return value of the cskeys()
- function.
-
- This is cskeys.
-
- With this it becomes very easy to make your own additions to the
- predefined keys in 'cskeys.h'.
-
-
- 22 HEAP
-
-
- 22.1 Purpose
-
- To avoid having to allocate many small blocks, a special HEAP class is
- implemented. The idea is to do allocations in chunks of about 2Kb and
- take the small amounts from that when needed.
-
- This approach has considerable advantages.
- - You can release all allocated memory with just one function call
- instead of freeing many small blocks separately.
- - It is a lot faster because normal heap operations are relatively
- slow.
- - Heap efficiency is also improved. It is much easier for the heap to
- deal with relatively few allocations of about 2Kb then it is to
- deal with numerous small allocations.
- - It can save valuable memory. There is considerable overhead
- involved in using the heap. Apart from what you need, several
- additional bytes are used to 'pointer' the allocated blocks
- together. In addition, allocations are done in multiples of 16
- bytes. This can lead to a situation where you need only 13
- bytes while 32 bytes are used!
-
-
- 22.2 When to use it?
-
- The HEAP class is particularly useful when dealing with pointer
- structures in ram. Pointer structures are small, all of the same size and
- an application will probably use a lot of them.
- The BUFFER class described earlier in this documentation also uses
- the HEAP class. This means you can use it without enlarging your
- application.
- The HEAP class assumes allocations of a fixed size. This limits its
- usefulness but improves efficiency. It is very well possible to use more
- then one instance of the HEAP class in an application. It is feasible to
- use a different HEAP for every size of allocation needed.
- The class was designed with small allocations in mind, something
- below 50 bytes. It is doubtful whether the HEAP class still makes sense
- for allocations above 100 bytes.
-
- Summarizing:
- - Allocations have to be of a fixed size.
- - Allocations have to be small, below 50 bytes.
- - Many allocations of this type are going to take place.
-
-
- 22.3 Using HEAP.
-
- Using the HEAP class starts of with an initialization, stating the size of
- the allocations. Afterwards the class has to be 'opened'. From there on
- allocations can be made, and blocks can be free-ed again. When the
- work is done, the close or the zap function can be called to free all
- allocated memory.
-
-
-
- // Example
-
- #include "csheap.h"
-
- void main(void)
- {
- typedef struct
- {
- void *next;
- void *prev;
- int number;
- } pStruct; // A typical pointer structure.
-
- HEAP heap; // HEAP class instance.
-
- heap.init(sizeof(pStruct)); // Initialize it for the size of the
- // pointer structure.
-
- heap.open(); // Open the class so it can be used.
-
- pStruct *p,*q;
-
- p=(pStruct *)heap.malloc(); // Allocation.
- q=(pStruct *)heap.malloc(); // Allocation.
-
- p.next=q.prev=NULL; // Doing something.
-
- // Doing much more.
-
- heap.free(q); // Freeing q.
-
- heap.close(); // Finally finished.
- // Freeing all allocated memory.
-
- }
-
-
-
-
- 22.4 Functions in alphabetical order.
-
- The function prototypes are in CSHEAP.H.
-
- void close(void);
- Closes the class. All allocated memory is freed. The
- initialisation parameters are retained, which makes it
- possible to reopen the class without calling init(). This
- function is also called by the class destructor.
- void empty(void );
- Frees all allocated memory, but the class remains
- open.
- void init(U16 alloc_size,U16 page_size=2048);
- Initializes the class. 'Alloc_size' is the size of the
- allocations needed. 'Page_size' is the size of the
- chunks which are going to be allocated from the
- heap. This parameter has a default value of 2048
- bytes.
- int open(void); Opens the class. The 'init()' function has to be called
- first. The function returns TRUE on success and
- FALSE otherwise.
- void free(void *p);
- Frees the previously allocated block 'p' is pointing at.
- void *malloc(void);
- Allocates a block and returns a pointer to it. If no
- memory is available, a NULL pointer is returned.
- void zap(void); Frees all allocated memory and closes the class. The
- initialization parameters set by the init() function are
- reset. This means the class has to be initialized again
- before it can be reopened.
-
-
- 23 Alloc-Logging
-
- 23.1 Introduction
-
- Dynamic memory allocations can create problems which are difficult to
- trace. Therefore, this library contains a set of functions which can be
- used to replace the normal malloc() and free() functions. The
- replacements can be made to write a record to a log. This log can be
- used later to check for memory leaks.
-
- The replacements also test for things like freeing a NULL pointer or a
- malloc which returns NULL. In the DOS version, Borlands 'heapcheck'
- functions are called to test for heap integrity.
-
- Replacements are preprocessor commands which can be switched on
- and off with the preprocessor variable CS_DEBUG.
- If CS_DEBUG is not defined, the normal functions are called.
-
- 23.2 Replacements
-
- Replacements are available for the following functions:
- Prototypes in csmalloc.h.
-
- Function: Replacement:
- malloc csmalloc
- calloc cscalloc
- realloc csrealloc
- free csfree
- farmalloc csfarmalloc
- farcalloc csfarcalloc
- farrealloc csfarrealloc
- farfree csfarfree
-
- The use of the replacements is fully equivalent to the original.
-
- The allocations in the CS-libraries are always done by calling the
- replacements. The production version of the libraries was compiled
- without CS_DEBUG being defined, so the normal functions are used
- and are called without any additional overhead. When the debug
- version was compiled, CS_DEBUG was defined and as a result all the
- allocations done by the library functions can be logged!
-
-
- 23.3 Logging
-
- Logging of allocations can be switched on and off through the use of
- two functions.
-
- void alloc_logging(int TrueFalse);
- After a call to alloc_logging(TRUE) all the allocations
- are logged in the ASCII file 'malloc.log'. Calling
- alloc_logging(FALSE) switches the logging off.
- void alloc_logging(int TrueFalse,char *name);
- This is basically the same as the previous function
- but has the additional option of specifying the name
- of the log file.
-
- The next example displays a part of an allocation log.
-
-
-
- 4E79:0004 file csedst30.cpp line 8: malloc() 8 bytes
- 4E7A:0004 file csedst30.cpp line 8: malloc() 8 bytes
- 4E78:0004 file csedst30.cpp line 23: free()
- 4E78:0004 file csedst30.cpp line 8: malloc() 9 bytes
- 4E79:0004 file csedst30.cpp line 23: free()
- 4E7B:0004 file csedst30.cpp line 8: malloc() 22 bytes
- 4E7B:0004 file csedst28.cpp line 12: realloc free()
- 4E7B:0004 file csedst28.cpp line 12: realloc malloc()
- 4E7A:0004 file csedstr.cpp line 15: free()
- 4E7B:0004 file csedstr.cpp line 15: free()
-
-
-
-
- As can be seen, the first column displays the pointer involved, the
- second and third display the file and the line where the call was made.
- When an allocation is concerned its size is also displayed. Reallocs
- appear as two lines.
-
-
- 23.4 Memory Leaks.
-
- With a log like this it is easy to check for memory leaks. In fact, a
- command-line utility is supplied to check for that. It is called
- CSMALLOC. Only one parameter needs to be supplied: the name of
- the allocation log.
-
- Example
-
- c:\test>CSMALLOC malloc.log
-
-
-
- If it encounters a malloc which is not matched by a free, it displays the
- pointer involved.
- Like:
-
- UNMATCHED address: 29CC:0004
-
-
-
- If all malloc's are matched by a free it says something like this:
-
- NO ERRORS encountered!!
-
-
- Number of addresses: 23
- Lowest address: 29CC:0004
- Highest address: 2EAE:0004
-
-
-
- If malloc logging is kept on for longer periods, the log file can become
- extremely large. However, this poses no problem for CSMALLOC.
-
- If you are planning to use this method to detect memory
- leaks, it is essential to switch on the logging before the first
- allocation is done. Don't forget class constructors do
- allocations as well!
- 24 CSEDSTR
-
-
- The class for manipulating strings. Instead of providing the formal
- syntax we will clarify things by supplying a large number of examples.
-
- Class name: EDSTR
- Prototypes are in CSEDSTR.H.
-
-
- #include "csedstr.h"
-
- main(void)
- {
- EDSTR str;
- str=" A test "; // Assign a string
- str.upper(); // Convert to upper case
- str.lower(); // Convert to lower case
- str.trim(); // Remove all leading and trailing blanks
- // str contains now: "a test";
- str+=" At the end "; // APPEND at the end
- // str contains now: "a test At the end"
- int i=-345;
- str=i; // Convert the integer value to string
- // str contains now: "-345";
- str="1001";
- i=str; // Assign string to integer
- str="A line";
- str.strip("ijkl"); // Stripping the characters i,j,k,l from
- // str.
- // Str now contains: "A ne";
- str="A line";
- str.filter("ijkl"); // Allow only the characters i,j,k,l in
- // str.
- // Str now contains: "li";
- str="The quick brown fox";
- str[4]='Q'; // Str now contains: "The Quick brown fox"
-
- EDSTR str2="by C++ !";
- str="Made possible ";
- str=str+str2; // Str: "Made possible by C++ !";
-
- if( str<str2) ..
- if( str>str2) ..
- if( str<=str2) ..
- if( str>=str2) ..
- if( str==str2) .. // Comparisons are possible.
- // Case is always ignored.
- gotoxy(5,20); clreol();
- str.edit(15,25); // User can edit the string.
- // Only 15 characters are displayed.
- // The maximal length of the string
- // is 25 characters.
- // The string will scroll if it
- // becomes longer then 15 characters.
- // 'Enter' or 'Escape' will
- // terminate the function.
- }
- 25 CSWINDOWS
-
- 25.1 Introduction
-
- The WINDOW class is an implementation of the well known
- character-based text windows.
-
- The window toolbox can be used in two distinct ways:
- 1) through the use of 'old-fashioned' C functions.
- 2) as a C++ class.
-
- The member functions of the WINDOW class are fine for manipulating
- one instance of the class, but the C-functions seem to have the
- advantage when dealing with more then one instance.
- E.g. shifting from one window to another or removing all windows at
- once involves more then one instance of the WINDOW class, so this is
- done by C-functions rather then class member functions.
-
- The examples above already gives you an impression of which
- functions to use when. When you are dealing with ONE window use the
- class, in all other cases use the global C functions.
- For the sake of completeness, the syntax of all the C-style functions is
- given, but whenever possible use the class member functions.
-
- For those who are becoming nervous:
- - You normally will need only two very simple C functions.
- - A few examples will make things clear!
-
-
- 25.2 General Information
-
- Class name: WINDOW
- Prototypes are in CSWINDOW.H.
-
- - Every window is uniquely identified by a positive integer number.
-
- - In practice the number of windows an application can use is only
- limited by the available amount of memory.
-
- - Windows can 'overlay' each other. When an underlying window is
- called to be brought to the top, some flickering may appear
- because the still overlying windows must first be removed, and
- later be replaced.
-
- - Checks are made to see if the window which has to be brought to
- the top is overlaid. If not, it will become immediately active.
-
- - The windows are 'chained' together. The windows which are used
- last are closest to the end of the chain. When you are worried
- about performance:
- a) try not to activate a window which is overlaid,
- b) use only windows close to the end of the chain.
- However, under normal circumstances you will never have to
- worry about performance, because the window functions are
- very fast.
-
-
- 25.3 The C++ version, the class WINDOW
-
-
- // Example:
-
- #include "dos.h"
- #include "cswindow.h"
-
- main(void)
- {
- WINDOW demo; // Declare a window
-
- demo.height(10); // The number of lines
- demo.width(40); // The number of columns
- demo.head(" A Demo Window ");// A text in the border
- demo.shadow(SHADOW); // Make a shadow
- demo.activate(); // Display the window
-
- gotoxy(5,5); // Write the famous
- cprintf(" Hello World !! "); // words in the window.
-
- waitkb(5000); // Wait 5 seconds.
-
- }
-
-
-
-
- 25.3.1 Syntax of the MEMBER functions
-
- void top(int) Sets the top row of the window. If you enter -1 the
- window is centered vertically on the screen.
- Default is -1.
- void left(int) Sets the left column if the window. If you enter -1 the
- window is centered horizontally on the screen.
- Default is -1.
- void height(int) Sets the height of the window.
- Default is 24.
- void width(int) Sets the width of the window.
- Default is 80.
- void set_dim(int top,int left,int height,int width)
- This set all four at once with this function.
- void border(int) Sets the border type. Four types are pre-defined in
- the header file CSWINDOW.H.
- 1: W_BORDER_NONE No border.
- 2: W_BORDER_SINGLE Border is a single line.
- 3: W_BORDER_DOUBLE Border is a double line.
- 4: W_BORDER_SPACE Border made out of 'space'
- is drawn around the
- window.
- The default is BORDER_SINGLE.
- void head(char *)
- Sets the heading text of the window. This text is at
- center of the top of the window, but only if a border is
- The maximum length of this string is 49 characters.
- The default is the empty string.
- void shadow(int)
- A value of 0 means no shadow, any other value will
- create a shadow. In CSWINDOW.H are two values
- pre-defined.
- 1: NO_SHADOW Don't display shadow.
- 2: SHADOW Display shadow.
- The default is NO_SHADOW.
- void activate(void)
- This makes the window appear on the screen, on top
- of all other windows. The first time it will also create
- the window. If the window already exists, but is lying
- beneath other windows, it is shifted to the top.
- void border_color(int)
- void screen_color(int)
- Sets the text-attribute of the border and the text
- screen. Notice: the text ATTRIBUTE. This means
- both the foreground and the background colors are
- set. This is implemented through a call to Borland's
- TEXTATTR() function. See their documentation for
- more information. You can also use the
- 'make_color()' function defined in 'cstools'.
- int border_color(void)
- Returns the text-attributes of the border.
- int screen_color(void)
- Returns the text-attributes of the screen.
- void clear(void) Clears the text screen.
- This is done automatically when the window is first
- created.
- void remove(void)
- Remove the window permanently. The previous
- active window will become the active window again.
- void remove_all(void)
- Removes ALL windows.
- int adjust(void) Even if the window already exists and is visible on
- the screen, you can make changes. Just call the
- appropriate functions ( e.g. height() to change the
- height etc.) and when you are done call 'adjust()'. The
- window will then change accordingly. The function
- returns TRUE if successful FALSE otherwise.
- int previous(void)
- Returns to the previous active window. That is: the
- window that was active before the current window
- became active. The function returns TRUE if
- successful FALSE otherwise.
- int user_adjust(void)
- This function gives the application user control over
- the window. He/she can change the position of the
- window with the cursor keys and the size through use
- of the control-cursor keys. The function ends when
- ENTER is pressed. The function returns TRUE if
- successful FALSE otherwise.
- void auto_delete(int)
- Sets the auto delete option. If called with a value
- unequal to 0, the window will be removed if the class
- instance is destructed. Otherwise the window will
- remain on the screen even if the class instance no
- longer exists. The default is ON.
- void scroll(int ROW,int COL)
- Make the text in the window scroll.
- ROW: scrolling up/down. A positive value means
- up (e.g. line 2 will become line 1).
- COL: scrolling left/right. A positive value means to
- the right (e.g. column 1 will become
- column 2).
- void get_dim(int *row,int *col,int *h,int *w)
- Returns the size-related-parameters of the window.
- The values returned do include the border but NOT
- the shadow.
- *row: Top row.
- *col: Left column
- *h: height
- *w: width
- These values need NOT be the same as the ones
- you assigned, because the window is adjusted to the
- limitations of the screen. (e.g. if you set height to 50,
- this function will tell you it is 25. )
- void get_in_dim(int *row,int *col,int *h,int *w)
- The same as the previous function but now the
- returned values do NOT include the border and do
- NOT include any shadow. So, the inner dimensions
- are returned.
- void work_size(int *height,int *width)
- Same as the previous function, but only the height
- and the width are returned.
- int number(void)
- Returns the number of the window. Only needed if
- you are using the C functions as well.
- 25.4 The C version
-
- As stated before, every window is identified by a unique integer
- number. In the C++ version you don't have to worry about this number.
- In the C version however, it is of prime importance. If a function has
- parameters, the first parameter is always the number of the window you
- are referring to.
-
- As pointed out in the introduction you are supposed to use the class
- functions whenever possible. In fact there are only two functions of the
- C version you should use.
-
- These are:
-
- int win_current(void);
- Returns the number of the current active window.
- You might need this number if you want to return to
- this window somewhere later on in your application.
- int win_shift(int num);
- Make window 'num' the active window. Useful in
- combination with the previous function.
-
-
- In rare cases:
-
- void win_remove_all(void);
- Remove all windows.
- int win_default(void);
- For writing outside any existing window.
-
- 25.4.1 Example
-
- Problem:
- You want to write an error handling function which writes a message at
- the bottom line of the screen and, after some waiting, returns to the
- original window and continues. The problem is, the function can be
- called from 'anywhere' and at the moment you are writing the function,
- it is not clear to which window to return.
-
-
-
- #include <......>
-
- WINDOW w_error; // Window for the messages, global...
-
- void disp_error(char *s)
- {
- int old_window=win_current(); // The window the function
- // is called from.
- w_error.activate(); // Make the error window
- // the active window.
- cprintf("\n\r %s ",s); // Print the text.
- wait(2500); // Wait 2.5 seconds.
- win_shift(old_window); // Return to the original window!
- }
-
- main(void)
- {
- w_error.set_dim(23,1,3,80);
- w_error.head(" E r r o r s ");
- w_error.activate(); // The window permanent visible
- // A lot of other windows
- // The program calls.
- }
-
-
- Note: In this simple example the 'previous' function also would have
- solved the problem. In more complicated cases however, this
- method can very well be the only solution.
-
-
- 25.5 Syntax of the C functions
-
- int win_make( int& num,
- int border_color,
- int screen_color,
- char *head,
- int top,
- int left,
- int height,
- int width,
- int border,
- int shadow);
-
-
- Parameters:
- num The number of the new window. If a window
- with this number already exists it is deleted.
- In the header file CSWINDOW.H is
- predefined W_NEW. If you call the function
- with 'num' equal to W_NEW a new window
- is created and num is changed into a
- number which was formerly not used. To
- make this possible num is passed by
- reference.
- border_color
- screen_color
- Sets the text-attribute of the border and the
- text screen.
- Notice: the text ATTRIBUTE. This means
- both the foreground and the background
- colors are set. This is implemented through
- a call to Borland's TEXTATTR() function.
- See their documentation for more
- information.
- head Sets the heading text of the window. This
- text is displayed at the center of the top of
- the window, but only if a border is present.
- top Sets the top row of the window. If you enter
- -1 the window is centered vertically on the
- screen.
- left Sets the left column if the window. If you
- enter -1 the window is centered horizontally
- on the screen.
- height Sets the height of the window.
- width Sets the width of the window.
- border Sets the border type. Four types are
- predefined in the header file CSWINDOW.H.
- 1: W_BORDER_NONE No border.
- 2: W_BORDER_SINGLE Border is a single
- line.
- 3: W_BORDER_DOUBLE Border is a
- double line.
- 4: W_BORDER_SPACE Border made out
- of 'space' is
- drawn around the
- window.
- void win_remove(void)
- Remove the active window from the screen. The
- previously active window will become the active
- window again.
- void win_remove_all(void)
- Removes ALL windows.
- int win_shift(int num)
- Will shift window with number 'num' to the top. The
- function returns TRUE if successful FALSE otherwise.
- int win_present(int num);
- Returns TRUE if window 'num' exists, FALSE
- otherwise.
- int win_first_unused(void)
- Returns the lowest positive number which is not 'in
- use' by a window.
- int win_current(void)
- Returns the number of the current active window. If
- no window is active it returns -1.
- void win_clear(void)
- Clears the current active window.
- int win_adjust( int num,
- int border_color,
- int screen_color,
- char *head,
- int top,
- int left,
- int height,
- int width,
- int border,
- int shadow);
- Is used to make changes to an existing window. The
- parameters are the same as with win_make(). Call
- this function with the parameters set to the newly
- desired values and your window will change
- accordingly. The function returns TRUE if successful
- FALSE otherwise.
- int win_previous(void)
- Returns to the previous active window. That is: the
- window that was active before the current window
- became active. The function returns TRUE if
- successful FALSE otherwise.
- int win_user_adjust(void)
- This function gives the application user control over
- the current active window. He/she can change the
- position by the cursor keys and the size by the
- control-cursor keys. The function ends when ENTER
- is pressed. The function returns TRUE if successful
- FALSE otherwise.
- void win_scroll(int num, int ROW,int COL)
- Make the text in the window 'num' scroll.
- ROW: scrolling up/down. A positive value means
- up (e.g. line 2 will become line 1).
- COL: scrolling left/right. A positive value means to
- the right (e.g. column 1 will become
- column 2).
- void win_get_dim(int num,int *row,int *col,int *h,int *w)
- Returns the size-related-parameters of window 'num'.
- The values returned do include the border but NOT
- the shadow.
- *row: Top row.
- *col: Left column
- *h: height
- *w: width
- These values need NOT be the same as the ones
- you assigned, because the window is adjusted to the
- limitations of the screen. (e.g. if you set height to 50,
- this function will tell you it is just 25. )
- void win_get_in_dim(int num,int *row,int *col,int *h,int *w)
- The same as the previous function but now the
- returned values do NOT include the border and do
- NOT include any shadow. So, the inner dimensions
- are returned.
- win_work_size(int num,int *height,int *width)
- Same as the previous function, but only the height
- and the width are returned.
- int win_default(void)
- Not a window at all. Intended for writing outside any
- existing window. The x,y coordinates are set back to
- the full screen, as it is when you are working without
- windows. The software represents this virtual window
- by number -1. This number can also be returned by
- the win_current() function.
-
- 25.6 Working within a Window
-
- Working within a window is the same for both versions. All the above
- mentioned functions are built around the compiler-supplied function
- window(). This means you can use all Borlands I/O functions that are
- intended to work relative to a window.
-
- The most important ones are:
- gotoxy(); // To move the cursor
- putch(); // Displaying a character in the window
- cputs(); // Displaying a string
- delline(); // Delete a line
- insline(); // Insert a line
- clrscr(); // Clears the window
- clreol(); // Clears until end of line
- getche(); // Read a character
- cgets(); // Read a string
- cprintf(); // Window version of printf()
- // Don't forget, you need "\n\r "
- // to go to the start of the next line.
- // cprintf("\n "); will put the cursor
- // one line down, without going to the
- // start of that line.
-
-
- 25.7 File Browsing
-
-
- The WINDOW class has a member funtion 'browse', which aid in
- displaying help-files.
-
-
- // Example
-
-
- WINDOW help; // Create Window for help text.
- help.set_dim(-1,-1,18,70); // Set size and position.
- help.head(" Help Screen "); // A Header.
- help.color(HlpBorCol,HlpScrCol); // Set the colors.
- help.browse("help.txt"); // Browse the help file.
-
-
-
- The help file has to be an ASCII file.
-
- Supported keys:
-
- ESC and ENTER: Exit.
- Cursor Up: 1 line up
- Cursor Down: 1 line down
- Page Up: 1 screen up.
- Page Down: 1 screen down.
- Home: Top of file.
- End: End of file.
-
- 26 CSMENU
-
-
- 26.1 General Information
-
- There are a lot of ways to implement a menu system. One very
- common method concentrates on directly calling functions from within
- the menu. This is not the method used here, because it seems to limit
- its usefulness.
-
- This menu system returns an integer value when an option is chosen.
- The idea is to make the return value equal to a certain function key
- connected with the option. The application user can then browse
- through the menus and select an option or hit the function key directly.
- In both cases your program has to deal with the same integer value
- which can easily be processed by applying a 'switch' statement.
-
- Examples will explain things further.
-
- There is no difference between a menu and a sub-menu. The definition
- is the same in both cases. The difference lies in the application of a
- 'connect' function which makes one menu the sub-menu of another.
-
- There are no limitations to the amount of menus you can use. The
- menus can be connected to arbitrary depth.
-
- The menus 'remember' which option was selected the last time the user
- was browsing through it. This option is again highlighted when the
- menu is entered.
-
- Function protypes are in csmenu.h.
-
-
- 26.2 Defining a menu
-
- int type(int hor_or_ver)
- Sets the type of the menu. There are two types:
- horizontal or vertical. In CSMENU.H two constants
- are predefined:
- MENU_HOR for a horizontal menu and
- MENU_VER for a vertical menu.
- The default is MENU_VER.
- void hold(int HoldRelease)
- A menu can be permanent on the screen or can be
- automatically removed after being used. This function
- allows you to control this. In CSMENU.H two
- constants are predefined:
- MENU_HOLD makes the menu remain on the screen
- and
- MENU_RELEASE which removes the menu
- afterwards.
- The default is MENU_RELEASE.
- void relative_pos(int ScreenCursor)
- The position of the menu can be set relative to the
- screen or relative to the cursor position at the
- moment of creation. ( Relative to the cursor is very
- convenient for submenus. ) In CSMENU.H two
- constants are predefined:
- TO_SCREEN for positions relative to the screen and
- TO_CURSOR for positions relative to the cursor.
- The default is TO_SCREEN.
- void top(int w)
- void left(int w)
- Sets the left column and the top row of the left-top
- corner of the menu. The coordinates are relative to
- the screen or the cursor, depending on the
- application of the relative_pos() function. If
- relative_pos is set to TO_SCREEN a value of -1 will
- center the menu.
- void width(int)
- void height(int)
- Sets the height and the width of the menu. If you
- don't use them or use zero, the appropriate values
- are calculated automatically. Advise: don't use them.
- int add_option(char *option,int key)
- Adds an option to the menu. The order in which they
- appear in the menu is the same as the order in which
- they are defined. The string 'option' defines the
- option-string. You can use a '~' to assign a key to the
- option. The return value is the value 'key'.
-
-
- Example:
- MENU m1;
- m1.add_option(" Se~tup ",123);
- // Defines option ' Setup ' as the first option
- // of menu m1. This option can also (apart
- // from using the cursor keys) being
- // selected by pressing 't' or 'T'.
- // If chosen, the menu system will return
- // the value 123.
-
-
- void enable_option(int num,int YesNo)
- With this function you control whether-or-not an
- option can be selected.
- Parameters:
- num Option number 'num'. The first option is
- number ONE.
- YesNo YesNo=TRUE means option is selectable.
- YesNo=FALSE means option can NOT
- being selected.
- By default all options are enabled.
- void enable_option(int YesNo)
- The same as the previous function, but applied to the
- last added option.
- void border_color(int)
- void screen_color(int)
- void option_color(int )
- void key_color(int )
- Sets the screen ATTRIBUTE of respectively the
- -border of the menu,
- -the 'normal' text in the menu, the not selected
- options.
- -the option which is currently selected
- -the hot key connected with the option
- Acceptable defaults are provided, depending on the
- type of screen.
- void color(int border, int screen, int option, int key)
- Sets all four colors at once.
-
-
- 26.3 Connecting menus
-
- The previous described functions are all concerned with defining just
- one menu. Of course you want to use a more complex menu structure
- which includes several sub-menus. The method to accomplish this is a
- simple one. Just define all submenus with the previously mentioned
- functions and then 'connect' them by calls to the connect(int, MENU &)
- function.
-
- int connect(int num, MENU &m2)
- Makes menu 'm2' a sub menu of this menu, 'dangling'
- under option 'num'. The first option is number ONE.
-
-
- Example:
- #include "cswindow.h"
- #include "cskeys.h"
- #include "csmenu.h"
-
- MENU m1,m2;
- m1.add_option(" File ", ALT_F);
- m1.add_option(" Setup ",ALT_S);
- m1.type(MENU_HOR);
- m1.left(1);
- m1.top(1);
- m1.border(BORDER_NONE);
- m2.add_option(" ~Load ", F3);
- m2.add_option(" ~Save ", F2);
- m2.left(1);
- m2.top(1);
- m2.relative_pos(TO_CURSOR);
- m1.connect(1,m2);
-
-
-
- 26.4 Displaying the menu
-
- void standby(void)
- If the menu is defined, it can be put on the screen by
- calling the standby() function. This will make all the
- (sub-) menus which are defined with MENU_HOLD
- become visible.
-
-
- 26.5 Using menus
-
- There are two ways to use the menu system:
-
- 1) The straightforward method.
- This is by a call to:
- int rc=choose(int &option).
-
- The user can select an option by using the cursor
- keys, escape, enter etc..
-
- Afterwards rc indicates the way the menu is left.
- If rc==ESC the menu is left by pressing the escape
- key, 'option' is undefined.
- If rc==ENTER the menu is left by pressing 'enter',
- and 'option' contains the return value corresponding
- with the selected option.
- 2) The hard way.
- In some, more complicated, cases the simple
- choose() function will not do, as is made clear by the
- following problem.
-
- Problem:
- Let's say you have a program in which the user
- can load a file by pressing F3. He also can reach
- the same option by browsing through the menus.
- Typically you want the load option to remain
- highlighted on the screen while your user is
- typing in the file name. How to accomplish this?
- Solution:
- The int show(int key) function is intended to
- solve this problem. Show(key) searches through
- the menus looking for the value 'key'. It returns
- TRUE if 'key' is found, FALSE otherwise.
- Assuming the required value is found, all the
- involved (sub-)menus are automatically
- displayed. Afterwards things can be brought back
- to normal by a call to standby().
-
- Example:
-
- #include "cswindow.h"
- #include "cskeys.h"
- #include "csmenu.h"
-
- MENU m1,m2;
- m1.add_option(" File ", ALT_F);
- m1.add_option(" Setup ",ALT_S);
- m1.type(MENU_HOR);
- m1.left(1);
- m1.top(1);
- m1.border(BORDER_NONE);
- m2.add_option(" ~Load ", F3);
- m2.add_option(" ~Save ", F2);
- m2.add_option(" e~Xit ", ALT_X);
- m2.left(1);
- m2.top(1);
- m2.relative_pos(TO_CURSOR);
- m1.connect(1,m2);
-
- m1.standby(); // Finally display something.
-
- int key;
- do
- {
- key=cskey(); // Read a key
- // ESC means browsing through the menus.
- if(key==ESC) m1.choose(key);
- // key now contains the option, either
- // by directly typing it in or selected
- // from the menu.
-
- switch(key)
- {
- case F3: // Loading a file.
- m1.show(F3);
- // Both the menus are now being
- // displayed.
- // The option 'load' is highlighted.
- //
- // You can now call the load function.
- load_function(); // Not defined.
- //
- m1.standby();
- // Bring the menu system back in its
- // default status.
- break;
- case F2: // Saving a file.
- // some
- // code to
- // save.
- break;
- }
- } while (key!=ALT_X); // Use ALT_X to terminate loop.
-
-
-
- Syntax:
-
- int choose(int &option)
- Use: int rc=choose(option);
-
- The user can select an option by using the cursor
- keys, escape, enter etc.. Afterwards rc indicates the
- way the menu is left. If rc==ESC the menu is left by
- pressing the escape key and 'option' is undefined. If
- rc==ENTER the menu is left by pressing 'enter', and
- 'option' contains the return value corresponding with
- the selected option.
- int choose_hold(int &option)
- Same as choose() but the selected option and the
- selected (sub)-menu(s) remain visible after the
- function has returned.
- int show(int key)
- Show(key) searches through the menus looking for
- the value 'key'. It returns TRUE if 'key' is found,
- FALSE otherwise. Assuming the required value is
- found, all the involved (sub-)menus are automatically
- displayed. Afterwards things can be brought back to
- normal by a call to standby().
-
-
- 26.6 Removing the menu
-
- void remove(void)
- By calling the remove() function the menu, including
- all sub-menus, will be removed.
-
-
-
-
- 27 CSPANEL
-
-
- 27.1 Purpose
-
- The PANEL class is intended to provide data entry screen much like
- the ones used by dBASE.
-
-
- Class name: PANEL
- Prototypes: cspanel.h.
-
- 27.2 General Information
-
- - This class is publicly derived from the window class. This implies
- that you can use all the functions from the window class to
- manipulate the panel window.
- - The default panel will appear both horizontally- and
- vertically-centered. The destructor of the class will remove, if
- needed, the panel and all fields.
- - The maximum number of fields in the panel is set to 35 by a
- preprocessor constant MAX_FIELDS. This value can NOT be
- increased. The variable is defined in the CSPANEL.H file.
- - The fields are numbered. The first field is numbered ZERO.
- - Fields can be made 'protected'. This means you cannot alter the
- contents of the field. The protection can be changed between
- successive calls to the read function (see below).
- - A 'changed' function is provided to determine whether-or-not
- something has been altered.
- - Functions are available to set the EXIT key and the EXIT field(s).
-
-
- 27.3 Public member functions
-
- void field_color(int col_att)
- Sets the default text ATTRIBUTE of each new added
- field.
- Meaning: each field which is added to the panel
- after a call to field_color() gets color
- col_att, unless this color is explicitly
- overwritten.
- int field_color(void)
- Returns this field attribute.
- void color(int border,int screen,int field)
- Sets the colors of the border, the screen and the
- field.
- int add_field( int top,
- int left,
- int color,
- int length,
- TYPE&PARM)
- This function adds an additional field to the panel.
- The function returns the number of fields defined so
- far (including the one you just added.)
- Parameters:
- top: The row of the field, relative to the panel.
- left: The left column of the field, relative to the
- panel.
- color: The color ATTRIBUTE of the field.
- length: The number of positions of the field.
- TYPE&PARM: One of the following:
- TYPE PARM
- char *s For a string field
- int &i For an integer field.
- long &l For a long field.
- float &f For a floating point field.
- double &d For a double field.
-
- int read(void)
- When the panel is adequately defined, the panel-user
- can be given control by a call to read(). The function
- returns when the user hits the exit-key or the ESC
- key. FALSE is returned if the panel is left by ESC,
- TRUE otherwise.
- int changed(void)
- Returns TRUE if the panel is actually changed during
- the last read. If nothing is changed, the function
- returns FALSE.
- int protect(int ebd)
- Intended to create a field which can NOT be edited.
- There are three options:
- - EDIT The default, the field can be edited.
- - BROWSE The cursor will not skip this field and
- you can let the string scroll but are not
- allowed to alter the contents.
- - DISPLAY The cursor will skip this field. The initial
- value will be displayed. This is applied
- to the last added field.
- The return value is TRUE if successful, FALSE
- otherwise.
- int protect(int FieldNum, int ebd)
- Same as protect(int ebd) but applied to field
- FieldNum.
- int exit_key(int KEY)
- Sets the key which makes the panel become
- 'accepted'. The default is ENTER in which case the
- ENTER key cannot be used to skip from one field to
- another. The ESC-key will always terminate the panel
- and will make the read function returns FALSE. The
- allowable keys are the ones defined in CSKEYS.H.
- int exit_field(int FieldNum, int YesNo)
- Normally the panel can be terminated no matter on
- which field the cursor is placed. After a call to
- exit_field(), the panel can only be terminated with the
- cursor standing on a field which is marked as an
- 'exit-field'.
- Calling exit_field(FieldNum,TRUE) marks field
- FieldNum as 'exit-field. Exit_field(FieldNum,FALSE)
- removes the mark.
- int exit_field(int YesNo)
- Same as exit_field(FieldNum,YesNo) except that it is
- applied to the last added field.
- void escape_off(void)
- void escape(int True_of_False)
- void escape_on(void)
- Escape_off() or escape(FALSE) disable the escape
- key. The panel can only be left by the 'exit-key'.
- Escape_on() or escape(TRUE) enables the escape
- key. This means the panel can be left by hitting
- escape.
- void remove(void)
- Remove the panel and all fields. All dynamically
- allocated memory is freed. This is also done by the
- destructor off the class.
- void date(int type)
- All the basic data types are automatically recognised
- by the add_field function. This is not so for dates. If
- you want a string to be treated as a date you have to
- call this function after the add_field() function.
-
-
- 27.4 Dates
-
- This paragraph describes the value of 'type' in the date(type) function.
-
- There are several different formats supported:
- Formats and the examples for April/25/1993.
-
- The formats are build out of:
- M Month
- D Day
- Y2 Year 2 positions
- Y4 Year 4 positions
-
- FORMAT: EXAMPLE:
-
- MDY2 04/25/93
- MY2D 04/93/25
- Y2MD 93/04/25
- Y2DM 93/25/04
- DMY2 25/04/93
- DY2M 25/93/04
- MDY4 04/25/1993
- MY4D 04/1993/25
- Y4MD 1993/04/25
- Y4DM 1993/25/04
- DMY4 25/04/1993
- DY4M 25/1993/04
-
- EXAMPLE:
-
- main(void)
- {
-
- char date_field[]="25/04/93";
- PANEL pan;
- pan.add_field(4,6,date_field);
- pan.date(MDY2);
-
- }
-
-
-
- 27.5 Fields
-
- The fields in the panel are instances of an independent class. They are
- derived from both the WINDOW class and the EDSTR class. This
- means that you can apply all the functions from these classes to each
- field independently.
-
- The modify a field you have the use the mod_field macro.
-
-
- EXAMPLE:
- // Suppose you want to change the color of a
- // specific field.
-
- #include "cspanel.h"
-
- main(void)
- {
-
- float balance=-345.87;
- int c_in_debt=make_color(RED,BLACK);
-
- PANEL pan;
- pan.add_field(2,3,10,balance);
- if(balance<0)
- { // display the figures in red if the
- // balance is negative.
- pan.mod_field.text_color(c_in_debt);
- }
-
- }
-
-
-
-
-
- The purpose of the macro is to hide a peculiar syntax.
-
- The 'pan.mod_field.text_color(c_debt)' is expanded into:
- pan.field().text_color(c_debt)
-
- If you have no objection against a syntax like that you can use it
- directly. In fact, if you want to change a field other then the last-added
- you have to use the function:
-
- FIELD& field(int num)
-
-
- EXAMPLE:
- // Suppose you want to put a border around field number
- // three ( Remember the first field is field ZERO.)
-
- PANEL pan;
-
- pan.add_field..... // Adding
- pan.add_field..... // Some
- pan.add_field..... // Fields
- pan.add_field..... //
- pan.add_field..... //
-
- pan.field(3).border(BORDER_SINGLE);
- // Change the color of the fourth field
-
-
-
-
-
- Functions:
- FIELD& field(void) To change the last added field.
- FIELD& field(int num) To change field 'num'.
- Macro:
- mod_field Same as field().
-
-
- 27.6 Using the panels
-
- A panel basically consists of a window and a number of fields. The
- fields can be changed by the 'mod_field' macro and the shape and size
- of the panel-window can be altered with the functions from the
- WINDOW class. However there is no special function to add normal
- text in the panel. Of course this is not needed because the normal
- gotoxy() and cprintf() functions can be used for that. But don't forget to
- 'activate' the panel before you write text in it.
-
- Example:
-
- #include "cspanel.h"
- main(void)
- {
-
- char str[]=" Some string ";
- char da[]="30/03/1987";
- PANEL panel;
-
- panel.set_dim(-1,-1,13,55); // These are
- panel.head(" A demo "); // all functions
- panel.border(BORDER_DOUBLE); // from the WINDOW class.
-
- panel.activate(); // DON'T FORGET THIS !!!
- // The panel is now visible
- // (Although without fields)
- gotoyx(2,10); cprintf("String: "); // Put text in the panel.
- panel.add_field(2,20,25,str); // Add a field.
-
- gotoyx(7,10); cprintf("Date: "); // Put text in the panel.
- panel.add_field(7,20,da); // Add a date field.
- panel.date(DMY4); // Date Format.
- panel.exit_key(F10); // Leave panel with F10.
-
- panel.read(); // Edit the data.
-
- }
-
- // Note: gotoyx() is used instead of gotoxy().
- // This is easier because the coordinates of the
- // add_field() functions also work in that way.
-
-
-
- 27.7 Data validation
-
- At the moment of writing the capabilities for data validation are limited.
- There exists a option to supply a maximum and a minimum value.
- Apart from that, there is a 'picture()' function to supply some crude sort
- of template. It isn't perfect, but it will do in most cases.
-
- Without 'anything' the next table applies:
-
- date: Are validated correctly, including leap-years.
- int: Accepts everything between -99999 and 99999.
- long: Accepts everything between -9999999999 and
- 9999999999.
- float and double:
- No checks for precision underflow or overflow. Accepts
- exponents between -999 and +999. No limits to the
- number of digits in the mantissa.
- string: No limitations.
- char: Everything of length 1 is accepted.
-
-
- When the user is editing a field, he/she is only allowed to skip to the
- next field if the value is considered 'valid'.
- When the 'escape' key is not disabled, the user can leave the panel
- with invalid values by hitting 'escape'.
-
-
- 27.7.1 Min and Max
-
- Syntax: void set_max(...);
- void set_min(...);
-
-
- Every type of field has its own set of functions to supply a maximum
- and a minimum value. These are inline functions which accept a type of
- parameter which may differ from the field type as long as it makes
- sence. E.g. a field of type 'long' has a set_max() function which accepts
- a 'int' but does not have a function which accepts a string.
-
-
-
- // Example Data Validation
-
- #include "csa.h"
-
- void main(void)
- {
-
- PANEL panel;
- int value=125;
-
- panel.set_dim(-1,-1,19,75); // Centre the panel on the screen.
- panel.head(" Data Validation ");
- panel.border(BORDER_DOUBLE);
- panel.activate();
-
- gotoyx(6,10); cprintf("Integer field ");
- panel.add_field(6,30,4,value); // Use 4 positions to edit 'value'.
- panel.mod_field.set_max(399); // Set the maximum value to 399.
- panel.mod_field.set_min(99); // Set the minimum value to 99.
-
- panel.read(); // Do the editing.
-
- }
-
-
-
- 27.7.2 Reset Max & Min
-
- Syntax: void reset_max(void);
- void reset_min(void);
-
- When the maximum or the minimum value is no longer required, it can
- be removed by a call to reset_max() or reset_min().
-
-
-
- // Example Reset max & min
-
- #include "csa.h"
-
- void main(void)
- {
-
- PANEL panel;
- int value=125;
-
- panel.set_dim(-1,-1,19,75); // Centre the panel on the screen.
- panel.head(" Data Validation ");
- panel.border(BORDER_DOUBLE);
- panel.activate();
-
- gotoyx(6,10); cprintf("Integer field ");
- panel.add_field(6,30,4,value); // Use 4 positions to edit 'value'.
- panel.mod_field.set_max(399); // Set the maximum value to 399.
- panel.mod_field.set_min(99); // Set the minimum value to 99.
-
- panel.read(); // Do the editing.
-
- panel.mod_field.reset_max(); // Reset the maximum value.
- panel.mod_field.reset_min(); // Reset the minimum value.
-
- panel.read(); // Edit again.
-
- panel.remove(); // Remove the panel from the screen.
-
- }
-
-
- 27.7.3 Templates
-
- Templates are used to specify more accuretly the format of the field.
- This is done by describing the field position-by-position.
-
- Next is a table indicating which symbols can be used in the template
- and what they mean.
-
- n 0123456789-+ Blank allowed.
- N 0123456789-+ Blank NOT allowed.
- o 0123456789 Blank allowed.
- O 0123456789 Blank NOT allowed.
- p 123456789-+ Blank allowed.
- P 123456789-+ Blank NOT allowed.
- q 123456789 Blank allowed.
- Q 123456789 Blank NOT allowed.
- s -+ Blank allowed.
- S -+ Blank NOT allowed.
- A The characters from the alfabet. Blanks NOT allowed.
- a The characters from the alfabet including blanks, ,.;: etc.
- B A but displayed as capital. (Not implemented yet.)
- b a but displayed as capital. (Not implemented yet.)
- C A or O
- c a or n
-
- Or in a table:
-
- ╔════════╤═══════╤════════╤═════════╤═════════╤════════════════╤══════════════╗
- ║ │ 12345 │ 0 │ +- │ blank │ abcdefghijk │ ~`!@#$%^ ║
- ║ │ 6789 │ │ │ │ lmnopqrstu │ &*()_=|\}{[]"║
- ║ │ │ │ │ │ vwxyz │ :;'?><,./ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ n │ x │ x │ x │ x │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ N │ x │ x │ x │ │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ o │ x │ x │ │ x │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ O │ x │ x │ │ │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ p │ x │ │ x │ x │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ P │ x │ │ x │ │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ q │ x │ │ │ x │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ Q │ x │ │ │ │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ s │ │ │ x │ x │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ S │ │ │ x │ │ │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ a │ │ │ x │ x │ x │ x ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ A │ │ │ │ │ x │ ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ c │ x │ x │ x │ x │ x │ x ║
- ╟────────┼───────┼────────┼─────────┼─────────┼────────────────┼──────────────╢
- ║ C │ x │ x │ │ │ x │ ║
- ╚════════╧═══════╧════════╧═════════╧═════════╧════════════════╧══════════════╝
-
-
-
- A template can be applied to a field by calling the 'picture()' function.
-
- Syntax:
- void picture(char *temp);
-
- The template itself is respresented as a string.
- When a template string is used, only the first 127 characters
- from the ASCII set can be used (reliable) in editing the field!!
-
-
- Example:
-
- #include "csa.h"
-
- void main(void)
- {
-
- PANEL panel;
- int value=125;
-
- panel.set_dim(-1,-1,19,75); // Centre the panel on the screen.
- panel.activate();
-
- panel.add_field(6,30,3,value); // Use 3 positions to edit 'value'.
- panel.mod_field.picture("QOO"); // A 3 positions integer. No blanks.
- // The first pos is not a '0'.
- // No -+ allowed/
-
- panel.read(); // Do the editing.
-
- panel.remove(); // Remove the panel from the screen.
-
- }
-
-
- When a character other then one from the table, appear in the template
- string, this character becomes a mandatory setting of the field at that
- particular position.
-
-
- Example:
-
- PANEL panel;
- char *str;
-
- .......
- panel.add_field(6,10,9,str);
- panel.mod_field.picture("tel:AAAAA");
- .....
- ...
-
-
- In this example the string will be 9 positions of which the first 4 will be
- 'tel:'. The last 5 will be freely editable, although only the characters from
- the alfabet are allowed.
-
- This setup works fine until you want to use one of the template codes
- as a literal. To facilitate in that, a 'special' character is supplied. This is
- the '@' character.
-
- E.g.: the template string "phone:AAAAA" will probably not do what you
- want, because the p,o,n are interpreted according to the table above.
- You have to use the string "@ph@o@ne:AAAAA" instead.
-
- It is possible to supply only a limited number of options at a specific
- position. For this, there is a special 'or' syntax.
-
-
- Example:
- ...mod_field.picture("o.oo[e|E]o");
-
-
- In this example there has to be a 'e' or a 'E' at the fourth position.
- Nothing else will be allowed.
- The or syntax takes the form of:
- [option1|option2].
-
- The "or's" can be nested:
-
-
- Example:
- ...mod_field.picture("[oooooo|o.oo[e|E]o]");
-
-
- The length of the options has to be the same. Note that 'e' is
- of the same length as 'E' and 'oooooo' is 6 positions just as
- 'o.oo[e|E]o'.
-
- More then two options are also allowed:
-
-
- Example:
- ...mod_field.picture("o.oo[f|F|e|E]o");
-
-
-
- 28 Registration Form
-
-
-
-
- Name: __________________________________________
-
- Address: __________________________________________
-
- _____________________________________
-
- City/State: __________________________________________
-
- Country: ______________________ Zip: ______________
-
- Telephone: (________) _________ - ____________________
-
-
- Diskette preference (circle one): 5.25 3.5
- If it's the same to you, please pick 3.5.
-
-
-
- Number Price F Price $
- (Dutch Guilders) (American Dollars)
-
-
- CS-Libraries _________ at f 200.- or $ 125.-
-
-
-
-
- Total enclosed f ______ or $ _____
-
-
-
-
- What would you like to see added or changed in the CS-Libraries?
-
- _____________________________________________________________
- _____________________________________________________________
- _____________________________________________________________
- _____________________________________________________________
- _____________________________________________________________
-
-
-
-
- Please, send completed form and check or money order to:
-
- Combis
- P.O. Box 3303
- 2280 GH RIJSWIJK
- The Netherlands
-
-
- Note: If this documentation is more then a year old, it is advisable to
- obtain a later version. Software, price and even address may
- have changed!